diff --git a/CLAUDE.md b/CLAUDE.md index c398999..1b7e511 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -33,7 +33,4 @@ uv run pytest ## Configuration -The tool requires these environment variables: -- `JENKINS_URL`: Jenkins server URL -- `JENKINS_USERNAME`: Jenkins username -- `JENKINS_PASSWORD` or `JENKINS_TOKEN`: API token or password +Credentials can be passed via command-line options (`-u/--url`, `-U/--username`, `-P/--password`) or environment variables (`JENKINS_URL`, `JENKINS_USERNAME`, `JENKINS_PASSWORD` or `JENKINS_TOKEN`). diff --git a/README.md b/README.md index 8294f26..f38aaa5 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,15 @@ uv run zzpyjenkins --help ## Configuration -Set the following environment variables: +You can provide Jenkins credentials via command-line options or environment variables: + +### Command-line options (preferred) + +```bash +zzpyjenkins -u https://jenkins.example.com -U username -P token info +``` + +### Environment variables ```bash export JENKINS_URL="https://your-jenkins-server.com" diff --git a/src/zzpyjenkins/cli.py b/src/zzpyjenkins/cli.py index 6afb7d3..79b6579 100644 --- a/src/zzpyjenkins/cli.py +++ b/src/zzpyjenkins/cli.py @@ -1,61 +1,69 @@ """Command-line interface for zzpyjenkins.""" import os -from pathlib import Path from typing import Optional import click -import jenkins from rich.console import Console -from rich.table import Table from .jenkins_client import JenkinsClient console = Console() -def get_client() -> JenkinsClient: - """Create Jenkins client from environment variables or config.""" - url = os.environ.get("JENKINS_URL") - username = os.environ.get("JENKINS_USERNAME") - password = os.environ.get("JENKINS_PASSWORD") or os.environ.get("JENKINS_TOKEN") +@click.group() +@click.option("--url", "-u", help="Jenkins server URL (default: JENKINS_URL env)") +@click.option("--username", "-U", help="Jenkins username (default: JENKINS_USERNAME env)") +@click.option("--password", "-P", help="Jenkins password/token (default: JENKINS_PASSWORD env)") +@click.version_option() +@click.pass_context +def main(ctx: click.Context, url: Optional[str], username: Optional[str], password: Optional[str]): + """A CLI tool to interact with Jenkins server for building jobs.""" + ctx.ensure_object(dict) + ctx.obj["url"] = url + ctx.obj["username"] = username + ctx.obj["password"] = password + + +def get_client(ctx: click.Context) -> JenkinsClient: + """Create Jenkins client from options or environment variables.""" + url = ctx.obj.get("url") or os.environ.get("JENKINS_URL") + username = ctx.obj.get("username") or os.environ.get("JENKINS_USERNAME") + password = ctx.obj.get("password") or os.environ.get("JENKINS_PASSWORD") or os.environ.get("JENKINS_TOKEN") if not all([url, username, password]): console.print("[red]Error: Missing Jenkins configuration.[/red]") - console.print("Set environment variables: JENKINS_URL, JENKINS_USERNAME, JENKINS_PASSWORD") + console.print("Use --url/--username/--password options or set environment variables:") + console.print(" JENKINS_URL, JENKINS_USERNAME, JENKINS_PASSWORD") raise SystemExit(1) return JenkinsClient(url, username, password) -@click.group() -@click.version_option() -def main(): - """A CLI tool to interact with Jenkins server for building jobs.""" - pass - - @main.command() -def info(): +@click.pass_context +def info(ctx: click.Context): """Show Jenkins server information.""" - client = get_client() + client = get_client(ctx) client.print_server_info() @main.command("list") @click.option("--pattern", "-p", default=None, help="Filter jobs by name pattern") -def list_jobs(pattern: Optional[str]): +@click.pass_context +def list_jobs(ctx: click.Context, pattern: Optional[str]): """List all jobs on Jenkins server.""" - client = get_client() + client = get_client(ctx) client.list_jobs(pattern) @main.command() @click.argument("job_name") @click.option("--params", "-p", multiple=True, help="Build parameters in KEY=VALUE format") -def build(job_name: str, params: tuple[str, ...]): +@click.pass_context +def build(ctx: click.Context, job_name: str, params: tuple[str, ...]): """Trigger a build for a job.""" - client = get_client() + client = get_client(ctx) # Parse parameters parameters = {} @@ -70,17 +78,19 @@ def build(job_name: str, params: tuple[str, ...]): @main.command() @click.argument("job_name") @click.argument("build_number", type=int, required=False) -def status(job_name: str, build_number: Optional[int]): +@click.pass_context +def status(ctx: click.Context, job_name: str, build_number: Optional[int]): """Get build status for a job.""" - client = get_client() + client = get_client(ctx) client.get_build_status(job_name, build_number) @main.command() @click.argument("job_name") -def watch(job_name: str): +@click.pass_context +def watch(ctx: click.Context, job_name: str): """Watch the latest build of a job in real-time.""" - client = get_client() + client = get_client(ctx) client.watch_build(job_name)