Add command-line options for Jenkins credentials

Allow passing URL, username, and password via global options (-u, -U, -P)
as an alternative to environment variables. Options take precedence over
environment variables.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-09 12:48:21 +08:00
parent 25ad8f3a71
commit 54838dba25
3 changed files with 46 additions and 31 deletions

View File

@@ -33,7 +33,4 @@ uv run pytest
## Configuration ## Configuration
The tool requires these environment variables: 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`).
- `JENKINS_URL`: Jenkins server URL
- `JENKINS_USERNAME`: Jenkins username
- `JENKINS_PASSWORD` or `JENKINS_TOKEN`: API token or password

View File

@@ -25,7 +25,15 @@ uv run zzpyjenkins --help
## Configuration ## 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 ```bash
export JENKINS_URL="https://your-jenkins-server.com" export JENKINS_URL="https://your-jenkins-server.com"

View File

@@ -1,61 +1,69 @@
"""Command-line interface for zzpyjenkins.""" """Command-line interface for zzpyjenkins."""
import os import os
from pathlib import Path
from typing import Optional from typing import Optional
import click import click
import jenkins
from rich.console import Console from rich.console import Console
from rich.table import Table
from .jenkins_client import JenkinsClient from .jenkins_client import JenkinsClient
console = Console() console = Console()
def get_client() -> JenkinsClient: @click.group()
"""Create Jenkins client from environment variables or config.""" @click.option("--url", "-u", help="Jenkins server URL (default: JENKINS_URL env)")
url = os.environ.get("JENKINS_URL") @click.option("--username", "-U", help="Jenkins username (default: JENKINS_USERNAME env)")
username = os.environ.get("JENKINS_USERNAME") @click.option("--password", "-P", help="Jenkins password/token (default: JENKINS_PASSWORD env)")
password = os.environ.get("JENKINS_PASSWORD") or os.environ.get("JENKINS_TOKEN") @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]): if not all([url, username, password]):
console.print("[red]Error: Missing Jenkins configuration.[/red]") 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) raise SystemExit(1)
return JenkinsClient(url, username, password) 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() @main.command()
def info(): @click.pass_context
def info(ctx: click.Context):
"""Show Jenkins server information.""" """Show Jenkins server information."""
client = get_client() client = get_client(ctx)
client.print_server_info() client.print_server_info()
@main.command("list") @main.command("list")
@click.option("--pattern", "-p", default=None, help="Filter jobs by name pattern") @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.""" """List all jobs on Jenkins server."""
client = get_client() client = get_client(ctx)
client.list_jobs(pattern) client.list_jobs(pattern)
@main.command() @main.command()
@click.argument("job_name") @click.argument("job_name")
@click.option("--params", "-p", multiple=True, help="Build parameters in KEY=VALUE format") @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.""" """Trigger a build for a job."""
client = get_client() client = get_client(ctx)
# Parse parameters # Parse parameters
parameters = {} parameters = {}
@@ -70,17 +78,19 @@ def build(job_name: str, params: tuple[str, ...]):
@main.command() @main.command()
@click.argument("job_name") @click.argument("job_name")
@click.argument("build_number", type=int, required=False) @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.""" """Get build status for a job."""
client = get_client() client = get_client(ctx)
client.get_build_status(job_name, build_number) client.get_build_status(job_name, build_number)
@main.command() @main.command()
@click.argument("job_name") @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.""" """Watch the latest build of a job in real-time."""
client = get_client() client = get_client(ctx)
client.watch_build(job_name) client.watch_build(job_name)