executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
jenkins-apiIntegrates with the Jenkins REST API via python-jenkins and JenkinsAPI to manage jobs, builds, pipelines, credentials, plugins, nodes, and folder organization.
Independent GitHub snapshot · Automated classification · Original documentation governs
name: jenkins-api description: Integrates with the Jenkins REST API via python-jenkins and JenkinsAPI to manage jobs, builds, pipelines, credentials, plugins, nodes, and folder organization. license: MIT compatibility: opencode metadata: version: "1.0.0" domain: coding triggers: jenkins api, python-jenkins, jenkinsapi, jenkins job, jenkins pipeline, jenkins build, jenkins plugin, jenkins credentials archetypes:
Integrates with the Jenkins REST API using python-jenkins and JenkinsAPI libraries to automate jobs, builds, pipelines, credentials, plugins, nodes, folders, and system configuration.
python-jenkins (jenkins.Jenkins) for server administration (jobs, plugins, nodes, credentials)JenkinsAPI (jenkinsapi.jenkins.Jenkins) for build-centric workflows (artifacts, revisions, blocking)tree query parameter to filter API responses and reduce payload sizejenkins.JenkinsException for auth failures and requests.exceptions.ConnectionError for connection issuesUse this skill when:
Avoid this skill for:
pipeline {} syntax and Groovy scripting)coding-kubernetes-api or coding-docker-api)Connect to Jenkins — Create a jenkins.Jenkins(url, username, password_or_token) instance. Use API tokens, not account passwords. Checkpoint: Call server.get_version() or server.get_whoami() to verify the connection and credentials.
Inspect Server State — Use server.get_jobs(), server.get_plugins(), server.get_nodes() to understand the current state. Checkpoint: Filter with depth=2 or the tree parameter to limit response size on large instances.
Manage Jobs — Use server.create_job(name, config_xml), server.copy_job(from_name, to_name), server.build_job(name, parameters). Job configurations use Jenkins XML format. Checkpoint: Verify the job appears in server.get_jobs() with the expected color/status.
Monitor Builds — Use server.get_build_info(name, number), server.get_build_console_output(name, number), or the JenkinsAPI job.get_last_build() method. Checkpoint: Check build['result'] for SUCCESS, FAILURE, UNSTABLE, or ABORTED.
Process Results — Extract artifacts with server.get_build_info()'s artifacts list, console output with get_build_console_output(), and test results through the REST API. Checkpoint: Verify artifact URLs are accessible via the Jenkins web UI.
import os
import xml.etree.ElementTree as ET
import jenkins
from jenkins import JenkinsException
def create_maven_job(
job_name: str,
git_repo_url: str,
maven_goals: str = "clean package",
branch: str = "*/main",
) -> dict:
"""Create a Jenkins Maven job with Git SCM configuration.
Args:
job_name: Name for the new Jenkins job.
git_repo_url: Git repository URL.
maven_goals: Maven goals to execute.
branch: Branch specifier.
Returns:
Dict with job name and creation status.
Raises:
JenkinsException: If connection or job creation fails.
"""
server = jenkins.Jenkins(
os.environ["JENKINS_URL"],
username=os.environ["JENKINS_USERNAME"],
password=os.environ["JENKINS_API_TOKEN"],
timeout=30,
)
# Build the config XML programmatically
project = ET.Element("project")
ET.SubElement(project, "description").text = f"Auto-created job: {job_name}"
scm = ET.SubElement(project, "scm", attrib={"class": "hudson.plugins.git.GitSCM"})
user_remote_configs = ET.SubElement(scm, "userRemoteConfigs")
remote_config = ET.SubElement(user_remote_configs, "hudson.plugins.git.UserRemoteConfig")
ET.SubElement(remote_config, "url").text = git_repo_url
branches = ET.SubElement(scm, "branches")
branch_spec = ET.SubElement(branches, "hudson.plugins.git.BranchSpec")
ET.SubElement(branch_spec, "name").text = branch
builders = ET.SubElement(project, "builders")
maven = ET.SubElement(
builders,
"hudson.tasks.Maven",
attrib={"mavenName": "Maven 3"},
)
ET.SubElement(maven, "targets").text = maven_goals
config_xml = ET.tostring(project, encoding="unicode")
try:
server.create_job(job_name, config_xml)
except JenkinsException as exc:
if "already exists" in str(exc):
# Job exists — reconfigure it
server.reconfig_job(job_name, config_xml)
return {"job_name": job_name, "status": "reconfigured"}
raise RuntimeError(
f"Failed to create Jenkins job '{job_name}': {exc}"
) from exc
return {"job_name": job_name, "status": "created"}
import os
import time
import jenkins
from jenkins import JenkinsException
import requests
def trigger_build_and_wait(
job_name: str,
parameters: dict | None = None,
poll_interval: int = 10,
timeout: int = 1800,
) -> dict:
"""Trigger a Jenkins build and wait for completion.
Args:
job_name: Name of the Jenkins job.
parameters: Build parameters for parameterized jobs.
poll_interval: Seconds between build status checks.
timeout: Maximum seconds to wait.
Returns:
Dict with build number, result, and console output.
Raises:
TimeoutError: If the build does not complete in time.
JenkinsException: If the Jenkins server returns an error.
"""
server = jenkins.Jenkins(
os.environ["JENKINS_URL"],
username=os.environ["JENKINS_USERNAME"],
password=os.environ["JENKINS_API_TOKEN"],
timeout=30,
)
# Trigger the build
next_build_number = server.get_job_info(job_name)["nextBuildNumber"]
server.build_job(job_name, parameters=parameters or {})
# Poll for completion
start = time.monotonic()
while time.monotonic() - start < timeout:
try:
build_info = server.get_build_info(job_name, next_build_number)
except JenkinsException:
# Build info may not be available immediately
time.sleep(poll_interval)
continue
if build_info.get("building", True):
time.sleep(poll_interval)
continue
# Build is complete — collect results
console_output = server.get_build_console_output(job_name, next_build_number)
return {
"job_name": job_name,
"build_number": next_build_number,
"result": build_info["result"],
"duration_ms": build_info.get("duration", 0),
"console_output": console_output,
"url": build_info["url"],
}
raise TimeoutError(
f"Build {job_name}#{next_build_number} did not complete within {timeout}s."
)
import os
import jenkins
from jenkins import JenkinsException
def install_plugins_and_create_node(
plugins: list[str],
node_name: str,
node_remote_fs: str = "/home/jenkins",
num_executors: int = 2,
labels: str = "linux docker",
) -> dict:
"""Install Jenkins plugins and create a new permanent agent node.
Args:
plugins: List of plugin short names to install.
node_name: Name for the new node.
node_remote_fs: Remote root directory on the node.
num_executors: Number of concurrent executors.
labels: Space-separated label list.
Returns:
Dict with installation status and node info.
"""
server = jenkins.Jenkins(
os.environ["JENKINS_URL"],
username=os.environ["JENKINS_USERNAME"],
password=os.environ["JENKINS_API_TOKEN"],
timeout=60,
)
# Install plugins
plugin_results: dict[str, str] = {}
for plugin in plugins:
try:
if server.get_plugin_info(plugin):
plugin_results[plugin] = "already_installed"
continue
except JenkinsException:
pass
try:
server.install_plugin(plugin)
plugin_results[plugin] = "installing"
except JenkinsException as exc:
plugin_results[plugin] = f"failed: {exc}"
# Create a permanent agent node
try:
server.create_node(
name=node_name,
num_executors=num_executors,
remote_fs=node_remote_fs,
labels=labels,
)
node_status = "created"
except JenkinsException as exc:
if "already exists" in str(exc):
node_status = "already_exists"
else:
node_status = f"failed: {exc}"
return {
"plugin_results": plugin_results,
"node": {"name": node_name, "status": node_status},
}
# ❌ BAD — no timeout, no version check, password instead of token
def connect_bad(url, user, password):
server = jenkins.Jenkins(url, user, password)
return server # May hang or silently fail auth!
# ✅ GOOD — typed, with timeout, version verification, and token auth
def connect_good(
url: str,
username: str,
api_token: str,
timeout: int = 30,
) -> jenkins.Jenkins:
"""Connect to a Jenkins server and verify credentials.
Args:
url: Full URL to Jenkins server (e.g., "https://jenkins.example.com").
username: Jenkins username.
api_token: Jenkins API token (from user profile).
timeout: Connection and read timeout in seconds.
Returns:
Authenticated Jenkins server instance.
Raises:
RuntimeError: If connection or authentication fails.
"""
if not url or not username or not api_token:
raise ValueError("Jenkins URL, username, and API token are required.")
server = jenkins.Jenkins(url, username, api_token, timeout=timeout)
try:
version = server.get_version()
user_info = server.get_whoami()
except JenkinsException as exc:
raise RuntimeError(
f"Failed to connect or authenticate to Jenkins at '{url}': {exc}"
) from exc
print(f"Connected to Jenkins v{version} as '{user_info.get('fullName', 'unknown')}'")
return server
jenkins.Jenkins connectionstree query parameter to filter API responses — ?tree=jobs[name,url,color] reduces payloads significantlyserver.get_whoami() to verify authentication immediately after connectingbuild['result'] is not None — a running build returns result: Noneget_build_info returns immediately after build_job — builds may be queued| Skill | Purpose |
|---|---|
coding-github-api | GitHub API for triggering Jenkins builds via webhooks |
coding-gitlab-api | GitLab CI/CD as an alternative to Jenkins pipelines |
coding-circleci-api | CircleCI API as a cloud-native CI/CD alternative |