Skip to content

aaronshaf/jk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

45 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

jk

Fast, API-driven Jenkins CLI for inspecting builds and failures. Built with Bun, TypeScript, and Effect.

Inspired by prior CLI work done by Evan Battaglia.

Quick Start

# 1. Install jk
bun install -g @aaronshaf/jk

# 2. Configure your Jenkins server
jk setup

# 3. Inspect failures (recursively finds root causes)
jk failures https://jenkins.example.com/job/MyProject/123/

# 4. Copy-paste any failure URL to get console output
jk console https://jenkins.example.com/blue/.../pipeline/534

# 5. For LLMs: Get XML output with smart filtering
jk failures --smart --xml https://jenkins.example.com/job/MyProject/123/ | pbcopy

Installation

Prerequisites: Bun runtime v1.0.0 or later

# Install Bun (if not already installed)
curl -fsSL https://bun.sh/install | bash

# Install jk globally
bun install -g @aaronshaf/jk

# Configure Jenkins credentials
jk setup

Getting a Jenkins API Token:

  1. Log in to Jenkins in your browser
  2. Click your username (top-right corner) → "Configure"
  3. Scroll to "API Token" section
  4. Click "Add new Token" or "Generate"
  5. Give it a name (e.g., "jk-cli") and click "Generate"
  6. Copy the token immediately (you won't be able to see it again!)

Setup options:

  • Direct storage: Credentials saved to ~/.config/jk/config.json (file permissions: 600)
  • Environment variables: Use JENKINS_USERNAME and JENKINS_API_TOKEN (more secure)

Commands

Inspect Builds

# View build information
jk build pipelines/MyProject/main/123

# View with full URL
jk build https://jenkins.example.com/job/MyProject/123/

List Recent Builds

# List recent builds for a job (no build number needed)
jk builds pipelines/MyProject/main

# List with full job URL
jk builds https://jenkins.example.com/job/MyProject/

# Show more builds (default: 5, max: 100)
jk builds --limit 10 pipelines/MyProject/main

# Get structured output for automation
jk builds --format xml pipelines/MyProject/main
jk builds --format json pipelines/MyProject/main

# Output only URLs (useful for piping to other commands)
jk builds --urls pipelines/MyProject/main | head -1 | jk failures

Inspect Failures

# List failed nodes (recursively traverses sub-builds by default)
jk failures pipelines/MyProject/main/456

# Pipe build number from stdin
echo "456" | jk failures

# Only inspect the specified build (no sub-builds)
jk failures --shallow pipelines/MyProject/main/456

# Show failures with full console output
jk failures --full pipelines/MyProject/main/456

# LLM-optimized output (reduces context window)
jk failures --smart --xml pipelines/MyProject/main/456
jk failures --tail 200 --xml pipelines/MyProject/main/456
jk failures --grep "ERROR|FATAL" --xml pipelines/MyProject/main/456

Console Output

# Traditional format (locator + node-id)
jk console pipelines/MyProject/main/456 node-123

# Copy-paste Blue Ocean URLs directly from failures output
jk console https://jenkins.example.com/blue/.../pipelines/MyProject/main/detail/main/154928/pipeline/534

# Pipe URL from stdin
echo "https://jenkins.example.com/blue/.../pipeline/534" | jk console

# Pipe to other tools
jk console <url> | grep ERROR
jk console <url> | less

Pro tip: Run jk failures to see all failed nodes with URLs, then copy-paste any URL directly into jk console.

Watch for Failures

Monitor one or more pipelines for new failures with live notifications:

# Watch a single pipeline
jk watch https://jenkins.example.com/job/MyProject/job/main/

# Watch multiple pipelines
jk watch \
  https://jenkins.example.com/job/MyProject/job/main/ \
  https://jenkins.example.com/job/MyProject/job/nightly/

# Custom poll interval (default: 60s)
jk watch --interval 30 https://jenkins.example.com/job/MyProject/

# Quiet mode (notifications only, no terminal UI)
jk watch --quiet https://jenkins.example.com/job/MyProject/

Keyboard controls:

  • c - Copy latest failure's smart XML analysis to clipboard
  • r - Refresh immediately
  • q - Quit

Features:

  • System notifications when builds fail (macOS/Linux)
  • Live countdown timer until next check
  • Press c to copy failure details (same as jk failures --smart --xml)
  • Only alerts on NEW failures (after watch starts)

Programmatic Usage

You can also use jk as a library in your Node.js or Bun projects:

# Install as a dependency
bun add @aaronshaf/jk
# or
npm install @aaronshaf/jk

Basic Example

import { Effect } from "effect";
import { createJenkinsClient, createBuildOperations, readConfig } from "@aaronshaf/jk";

const program = Effect.gen(function* () {
  // Load config from ~/.config/jk/config.json
  const config = yield* readConfig();

  // Create client and operations
  const client = yield* createJenkinsClient(config);
  const operations = createBuildOperations(client, config);

  // Get build nodes
  const nodes = yield* operations.getBuildNodes("pipelines/MyProject/main/123");

  console.log(`Found ${nodes.length} nodes`);

  // Get failed nodes
  const failures = yield* operations.getFailedNodes("pipelines/MyProject/main/123");
  console.log(`${failures.length} failures found`);
});

// Run the program
Effect.runPromise(program).catch(console.error);

Advanced Example with Error Handling

import { Effect, pipe } from "effect";
import {
  createJenkinsClient,
  createBuildOperations,
  readConfig,
  type FailureReport
} from "@aaronshaf/jk";

const analyzeFailures = (locator: string) =>
  Effect.gen(function* () {
    const config = yield* readConfig();
    const client = yield* createJenkinsClient(config);
    const operations = createBuildOperations(client, config);

    // Get failure report with console output (recursive by default)
    const failures: FailureReport[] = yield* operations.getFailureReportRecursive(
      locator,
      true // include full console output
    );

    // Process failures
    for (const failure of failures) {
      console.log(`\n${failure.displayName} (${failure.pipeline}/${failure.buildNumber})`);
      console.log(`URL: ${failure.url}`);
      if (failure.consoleOutput) {
        const errorLines = failure.consoleOutput
          .split('\n')
          .filter(line => /error|fail|exception/i.test(line));
        console.log(`Errors: ${errorLines.length} lines`);
      }
    }

    return failures;
  });

// Run with error handling
pipe(
  analyzeFailures("pipelines/MyProject/main/456"),
  Effect.catchAll((error) =>
    Effect.sync(() => {
      if (error._tag === "BuildNotFoundError") {
        console.error("Build not found:", error.message);
      } else if (error._tag === "AuthenticationError") {
        console.error("Authentication failed:", error.message);
      } else {
        console.error("Error:", error.message);
      }
      process.exit(1);
    })
  ),
  Effect.runPromise
);

Available Exports

// Main exports
import {
  // Client
  createJenkinsClient,
  type JenkinsHttpClient,

  // Operations
  createBuildOperations,
  type BuildOperations,

  // Configuration
  readConfig,
  writeConfig,
  createDefaultConfig,
  type Config,

  // Types
  type BuildNode,
  type FailureReport,
  type PipelineInfo,

  // Errors
  NetworkError,
  AuthenticationError,
  BuildNotFoundError,
  type AppError,
} from "@aaronshaf/jk";

// Subpath exports
import { parseLocator } from "@aaronshaf/jk/jenkins";
import { getConfigPath } from "@aaronshaf/jk/config";
import { ValidationError } from "@aaronshaf/jk/effects";

See the TypeScript declarations for the complete API.

Key Features

XML Output for LLMs

jk build --xml pipelines/MyProject/main/123
jk failures --xml pipelines/MyProject/main/456

XML output is optimized for consumption by LLMs (Claude, etc.) and provides structured, easily parseable build data.

Console output filtering (avoids context window explosions):

  • --smart: Last 100 lines + all error/fail/exception lines (recommended for LLMs)
  • --tail <n>: Last N lines only
  • --grep <pattern>: Lines matching regex pattern
  • --full: Full console output (can be very large)

All filters apply per failed node - when using --recursive, each sub-build failure is filtered individually.

Example LLM workflow:

# Extract failures for debugging
jk failures --smart --xml <build> | pbcopy
# Paste into Claude Code for analysis

Flexible Locator Formats

jk accepts multiple formats for identifying builds:

Build locators:

  • Full Jenkins URL: https://jenkins.example.com/job/MyProject/123/
  • Pipeline URL: https://jenkins.example.com/.../pipelines/MyProject/runs/123
  • Pipeline path: pipelines/MyProject/main/123
  • Pipeline with runs: pipelines/MyProject/main/runs/123

Node URLs (for jk console):

  • Blue Ocean node URL: https://jenkins.example.com/blue/.../pipelines/Project/Branch/detail/Branch/BuildNumber/pipeline/NodeId
  • Traditional: <locator> <node-id> (still supported)

Recursive Failure Inspection (Default)

By default, jk failures recursively traverses sub-builds to find root causes:

# Follows sub-builds automatically
jk failures pipelines/MyProject/main/456

# Explicitly request recursive (same as default)
jk failures --recursive pipelines/MyProject/main/456

# Opt out of recursion with --shallow
jk failures --shallow pipelines/MyProject/main/456

When a parent build triggers sub-builds (e.g., MyProject/main → test-suites/JS), the tool automatically gathers failures from all levels. This ensures you see the actual test failures instead of just "wrapper failed" messages.

Combine with filtering for optimal LLM analysis:

jk failures --tail 200 --xml pipelines/MyProject/main/456

Documentation

Upgrading

To upgrade jk to the latest version:

bun update -g @aaronshaf/jk

After upgrading, you may want to review new configuration options:

jk setup  # Review and update your configuration

License

MIT

About

Jenkins CLI

Resources

License

Stars

Watchers

Forks

Contributors