Last active
July 11, 2025 20:22
-
-
Save Java4all/404394ae83d77dedd554fc0293b97684 to your computer and use it in GitHub Desktop.
Jenkins plugin check
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
inal Version — jenkins_audit.py | |
python | |
#!/usr/bin/env python3 | |
import argparse | |
import os | |
import requests | |
from packaging.version import Version, InvalidVersion | |
from tabulate import tabulate | |
def get_arg_or_env(arg, env_var, required=False, default=None): | |
val = arg if arg is not None else os.environ.get(env_var) | |
if val is None and default is not None: | |
return default | |
if required and val is None: | |
raise SystemExit(f"Missing required: --{env_var.lower()} or env {env_var}") | |
return val | |
def is_compatible(installed, required): | |
# Convert to string, strip quotes and whitespace | |
installed = str(installed or "").strip().strip("'\"") | |
required = str(required or "").strip().strip("'\"") | |
if not installed or not required: | |
return False # empty → not compatible | |
try: | |
return Version(installed) >= Version(required) | |
except InvalidVersion: | |
# Log and fallback to lexical comparison | |
print(f"⚠️ Non-PEP version fallback: '{installed}' vs '{required}'") | |
return installed == required or installed > required | |
def get_installed_plugins(jenkins_url, user, token): | |
url = f"{jenkins_url}/pluginManager/api/json?depth=1" | |
resp = requests.get(url, auth=(user, token)) | |
resp.raise_for_status() | |
return { | |
p["shortName"]: p["version"] | |
for p in resp.json().get("plugins", []) | |
} | |
def fetch_plugin_metadata(plugin_id): | |
url = f"https://plugins.jenkins.io/api/plugin/{plugin_id}" | |
resp = requests.get(url) | |
resp.raise_for_status() | |
data = resp.json() | |
return data["version"], data.get("dependencies", []) | |
def build_plugin_tree(plugin_id, max_depth=3, depth=0, seen=None): | |
if seen is None: | |
seen = {} | |
if depth > max_depth: | |
return seen | |
version, deps = fetch_plugin_metadata(plugin_id) | |
seen[plugin_id] = {"version": version, "depth": depth} | |
for dep in deps: | |
dep_id = dep["name"] | |
dep_ver = dep.get("version", "") | |
current = seen.get(dep_id) | |
should_recurse = current is None or Version(dep_ver) > Version(current["version"]) | |
if should_recurse: | |
seen[dep_id] = {"version": dep_ver, "depth": depth + 1} | |
build_plugin_tree(dep_id, max_depth, depth + 1, seen) | |
return seen | |
def compute_impact(installed, new_tree): | |
report = [] | |
for plugin, meta in new_tree.items(): | |
required = meta["version"] | |
depth = meta["depth"] | |
installed_ver = installed.get(plugin) | |
if installed_ver: | |
if is_compatible(installed_ver, required): | |
action = "✅ Compatible" | |
else: | |
action = f"🔺 Upgrade (has {installed_ver})" | |
else: | |
action = "❌ Not Installed" | |
report.append([depth, plugin, required, installed_ver or "-", action]) | |
return sorted(report, key=lambda x: x[0]) | |
def main(): | |
p = argparse.ArgumentParser(description="Jenkins Plugin Compatibility Audit Tool") | |
p.add_argument("--url", help="Jenkins URL") | |
p.add_argument("--user", help="Jenkins username") | |
p.add_argument("--token", help="Jenkins API token") | |
p.add_argument("--plugin-id", help="Target plugin ID to audit") | |
p.add_argument("--depth", type=int, help="Max dependency depth", default=None) | |
args = p.parse_args() | |
j_url = get_arg_or_env(args.url, "JENKINS_URL", required=True) | |
j_user = get_arg_or_env(args.user, "JENKINS_USER", required=True) | |
j_tok = get_arg_or_env(args.token, "JENKINS_TOKEN", required=True) | |
pid = get_arg_or_env(args.plugin_id, "JENKINS_PLUGIN_ID", required=True) | |
max_d = get_arg_or_env(args.depth, "JENKINS_DEPTH", default=3) | |
print(f"\n🔧 Fetching installed plugins from {j_url}") | |
installed = get_installed_plugins(j_url, j_user, j_tok) | |
print(f"🌱 Building dependency tree for '{pid}' (max depth {max_d})") | |
new_tree = build_plugin_tree(pid, max_depth=int(max_d)) | |
print(f"\n📊 Auditing impact of installing '{pid}'…") | |
report = compute_impact(installed, new_tree) | |
print("\n📋 Impact Report (depth-aware):\n") | |
print(tabulate( | |
report, | |
headers=["Depth", "Plugin", "Required", "Installed", "Impact"], | |
tablefmt="fancy_grid" | |
)) | |
print() | |
if __name__ == "__main__": | |
if os.environ.get("JENKINS_AUDIT_DRY_RUN"): | |
print("🚧 Dry run mode not implemented yet!") | |
else: | |
main() | |
📄 README.md (Updated with Depth Flag) | |
markdown | |
# 🧩 Jenkins Plugin Compatibility Audit CLI | |
This CLI tool audits the impact of installing a Jenkins plugin — checking its versioned dependencies up to a configurable depth against an active Jenkins instance. | |
--- | |
## 🚀 Features | |
- 🔍 Audits any plugin via [plugins.jenkins.io](https://plugins.jenkins.io) | |
- 🔐 Connects to Jenkins via REST API using user/token | |
- 🌳 Recursively builds depth-aware plugin dependency trees | |
- 📊 Compares with installed plugin versions | |
- ✅ Flags version upgrades and missing dependencies | |
- 🌱 Uses CLI flags or environment variables | |
--- | |
## 🛠️ Requirements | |
- Python 3.7+ | |
- Install dependencies: | |
```bash | |
pip install requests packaging tabulate | |
💻 Usage | |
CLI Flags | |
bash | |
python jenkins_audit.py \ | |
--url http://localhost:8080 \ | |
--user admin \ | |
--token myapitoken \ | |
--plugin-id git \ | |
--depth 3 | |
Environment Variable Fallback | |
bash | |
export JENKINS_URL=http://localhost:8080 | |
export JENKINS_USER=admin | |
export JENKINS_TOKEN=myapitoken | |
export JENKINS_PLUGIN_ID=git | |
export JENKINS_DEPTH=3 | |
python jenkins_audit.py | |
📋 Example Output | |
plaintext | |
📋 Impact Report (depth-aware): | |
╒════════╤════════════╤═══════════╤════════════╤══════════════════════╕ | |
│ Depth │ Plugin │ Required │ Installed │ Impact │ | |
╞════════╪════════════╪═══════════╪════════════╪══════════════════════╡ | |
│ 0 │ git │ 5.2.0 │ - │ ❌ Not Installed │ | |
├────────┼────────────┼───────────┼────────────┼──────────────────────┤ | |
│ 1 │ credentials│ 2.3.0 │ 2.1.19 │ 🔺 Upgrade (has 2.1.19)│ | |
├────────┼────────────┼───────────┼────────────┼──────────────────────┤ | |
│ 2 │ scm-api │ 2.6.0 │ 2.5.0 │ 🔺 Upgrade (has 2.5.0) │ | |
╘════════╧════════════╧═══════════╧════════════╧══════════════════════╛ | |
🧪 Test Mode | |
Dry-run mode coming soon! | |
📄 License | |
MIT — free to use, fork, extend, and share. | |
--- | |
You’re now wielding a CLI that does layered, depth-aware dependency analysis like |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment