Skip to content

Instantly share code, notes, and snippets.

@Java4all
Last active July 11, 2025 20:22
Show Gist options
  • Save Java4all/404394ae83d77dedd554fc0293b97684 to your computer and use it in GitHub Desktop.
Save Java4all/404394ae83d77dedd554fc0293b97684 to your computer and use it in GitHub Desktop.
Jenkins plugin check
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