@ts-org/jenkins-cli 3.1.2 → 3.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/cli.js +27 -24
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -251,6 +251,13 @@ jenkins-cli plugin show
|
|
|
251
251
|
jenkins-cli plugin backup -d ./jenkins-backup
|
|
252
252
|
```
|
|
253
253
|
|
|
254
|
+
#### `backup` - full Jenkins backup
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
# Back up Jenkins global config, jobs, plugins, and credentials
|
|
258
|
+
jenkins-cli backup -d ./jenkins-backup
|
|
259
|
+
```
|
|
260
|
+
|
|
254
261
|
#### `console` - view logs
|
|
255
262
|
|
|
256
263
|
Supports live log following, enabled by default.
|
package/dist/cli.js
CHANGED
|
@@ -1,44 +1,47 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { program, CommanderError } from 'commander';
|
|
3
|
-
import
|
|
3
|
+
import ce from 'inquirer';
|
|
4
4
|
import y from 'chalk';
|
|
5
|
-
import
|
|
5
|
+
import un from 'ora';
|
|
6
6
|
import { exec, spawn } from 'child_process';
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
7
|
+
import _n, { promisify } from 'util';
|
|
8
|
+
import _ from 'fs-extra';
|
|
9
|
+
import vn from 'js-yaml';
|
|
10
|
+
import W from 'path';
|
|
11
|
+
import En from 'axios';
|
|
12
12
|
import { Buffer } from 'buffer';
|
|
13
|
-
import
|
|
13
|
+
import Vn from 'jiti';
|
|
14
14
|
import { fileURLToPath } from 'url';
|
|
15
15
|
import { promises } from 'fs';
|
|
16
16
|
import { XMLParser } from 'fast-xml-parser';
|
|
17
|
-
import
|
|
17
|
+
import lr from 'os';
|
|
18
18
|
|
|
19
|
-
var
|
|
19
|
+
var it="3.1.3",st="Jenkins deployment CLI";var g=class extends Error{hint;example;details;exitCode;constructor(t,e={}){super(t),this.name="UserError",this.hint=e.hint,this.example=e.example,this.details=e.details,this.exitCode=e.exitCode??1;}};function jn(n){return n instanceof g?n:n instanceof CommanderError?new g(n.message,{hint:"Check the command usage and options.",example:"jenkins-cli --help",exitCode:n.exitCode??1}):n instanceof Error?new g(n.message,{hint:"Check your input and try again.",example:"jenkins-cli --help"}):new g("Unknown error",{example:"jenkins-cli --help"})}function M(n){let t=jn(n);if(console.error(y.red(`
|
|
20
20
|
\u274C ${t.message}
|
|
21
|
-
`)),t.details&&console.error(y.gray(t.details)),t.hint&&console.error(y.yellow(`Hint: ${t.hint}`)),t.example!==""){let e=t.example??"jenkins-cli --help";console.error(y.cyan(`Example: ${e}`));}console.error(y.gray('Run "jenkins-cli --help" for usage.')),process.exitCode=t.exitCode;}var
|
|
22
|
-
`).filter(t=>t.includes("/")&&!t.includes("HEAD"))}catch{throw new
|
|
21
|
+
`)),t.details&&console.error(y.gray(t.details)),t.hint&&console.error(y.yellow(`Hint: ${t.hint}`)),t.example!==""){let e=t.example??"jenkins-cli --help";console.error(y.cyan(`Example: ${e}`));}console.error(y.gray('Run "jenkins-cli --help" for usage.')),process.exitCode=t.exitCode;}var Ue=promisify(exec);async function at(){try{let{stdout:n}=await Ue("git branch --show-current"),t=n.trim();if(!t)throw new g("Not on any branch (detached HEAD state).",{hint:"Checkout a branch before running this command.",example:"git checkout main"});return t}catch{throw new g("Failed to get current branch.",{hint:"Make sure you are inside a git repository.",example:"cd /path/to/repo && jenkins-cli"})}}async function ct(){try{let{stdout:n}=await Ue('git branch -r --format="%(refname:short)"');return n.split(`
|
|
22
|
+
`).filter(t=>t.includes("/")&&!t.includes("HEAD"))}catch{throw new g("Failed to list branches.",{hint:"Make sure you are inside a git repository.",example:"cd /path/to/repo && jenkins-cli"})}}async function fe(){try{let{stdout:n}=await Ue("git config user.name"),t=n.trim();return t||void 0}catch{return}}var z="jenkins-cli.yaml",ge="package.json",de="jenkins-cli",$n="jenkinsCli";function ut(n,t=process.cwd()){let e=t;for(;;){let r=W.join(e,n);if(_.existsSync(r))return r;let o=W.dirname(e);if(o===e)return null;e=o;}}function Jn(n=process.cwd()){return ut(z,n)}function Pn(n=process.cwd()){let t=ut(ge,n);return t?W.dirname(t):null}function Rn(n){let t=Array.isArray(n.modes)&&n.modes.length>0||typeof n.modes=="string";return !!(n.apiToken&&n.job&&t)}async function lt(n){let t=await _.readFile(n,"utf-8"),e=vn.load(t);if(!e||typeof e!="object")throw new g(`Invalid config in ${z}. Expected a YAML object.`,{hint:"Top-level config must be key/value pairs.",example:`${z}:
|
|
23
23
|
apiToken: http://user:token@host
|
|
24
24
|
job: my-job
|
|
25
|
-
modes: [dev]`});return e}async function
|
|
25
|
+
modes: [dev]`});return e}async function Nn(n){let t=W.join(n,ge);if(!await _.pathExists(t))return {};let e=await _.readFile(t,"utf-8"),r=JSON.parse(e),o=r[de]??r[$n];if(o==null)return {};if(typeof o!="object"||Array.isArray(o))throw new g(`Invalid ${ge} config: "${de}" must be an object.`,{hint:"Use an object for the config section.",example:`"${de}": { "apiToken": "http://user:token@host", "job": "my-job", "modes": ["dev"] }`});return o}async function mt(){let n=process.cwd(),t=Pn(n)??n,e=W.join(t,z),r={},o=W.dirname(t),s=Jn(o);s&&await _.pathExists(s)&&(r=await lt(s));let i=await Nn(t);r={...r,...i};let a=await _.pathExists(e)?await lt(e):{};if(r={...r,...a},!Rn(r))throw new g("Config incomplete or not found.",{hint:`Tried ${z} in project root, "${de}" in ${ge}, and walking up from cwd. Required: apiToken, job, modes (non-empty array).`,example:`${z}:
|
|
26
26
|
apiToken: http://user:token@host
|
|
27
27
|
job: my-job
|
|
28
28
|
modes:
|
|
29
|
-
- dev`});return {...r,projectRoot:t}}var
|
|
30
|
-
`);return _(fe(s))}function Rn(n){let t=[...n.matchAll(/<tr[^>]*>([\s\S]*?)<\/tr>/gi)],e=[],r=new Set;for(let s of t){let i=s[1]??"",a=[...i.matchAll(/<a[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/gi)],c="",l="";for(let v of a){let L=v[1]??"",R=_(fe(v[2]??"")).trim();if(!(!R||R==="..")&&!/all\s+files\s+in\s+zip/i.test(R)){c=L,l=R;break}}if(!c||!l||c==="../"||c==="..")continue;let u=/class="[^"]*folder[^"]*"/i.test(i)||c.endsWith("/")?"dir":"file",m=_(c.split("?")[0]??"").replace(/\/+$/,"")||l,f=i.match(/class="last-modified"[^>]*>([\s\S]*?)<\/td>/i),d=f?_(fe(f[1]??"")).trim():"",g=d?Z(d):void 0,b=`${l}|${m}`;r.has(b)||(r.add(b),e.push({name:l,path:m,type:u,modified:g}));}if(e.length)return e;let o=[...n.matchAll(/<a[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/gi)];for(let s of o){let i=String(s[1]??"").trim(),a=_(fe(s[2]??"")).trim();if(!a||a===".."||/all\s+files\s+in\s+zip/i.test(a)||!i||i==="../"||i===".."||/^https?:\/\//i.test(i)||i.startsWith("/")||i.startsWith("?")||i.startsWith("#")||/\/job\//i.test(i)||/\/view\//i.test(i))continue;let c=i.endsWith("/")?"dir":"file",l=_(i.split("?")[0]??"").replace(/\/+$/,"")||a,u=`${a}|${l}`;r.has(u)||(r.add(u),e.push({name:a,path:l,type:c}));}return e}async function Ue(n,t,e){let r=We(t,`ws/${e}`),o=[`${r}?format=raw`,`${r}?format=txt`,`${r}?format=plain`,`${r}?plain=1`,`${r}?raw=1`,r],s;for(let i of o)try{let a=await n.axios.get(i,{responseType:"arraybuffer",headers:{Accept:"*/*"}}),c=a.data??new ArrayBuffer(0),l=Buffer.from(c);if(!l.length)continue;let u=a.headers?.["content-type"];return {data:l,contentType:u?String(u):void 0}}catch(a){if(s=a,a?.response?.status===404)continue;throw a}throw s||new Error("Workspace file not found")}async function Le(n,t,e){let r=We(t,`ws/${e}`),o=[`${r}?format=raw`,`${r}?format=txt`,`${r}?format=plain`,`${r}?plain=1`,`${r}?raw=1`,r],s;for(let i of o)try{let a=await n.axios.get(i,{responseType:"text",headers:{Accept:"text/plain,*/*"}}),c=typeof a.data=="string"?a.data:String(a.data??"");if(!c)continue;if($n(c)){let l=Jn(c);if(l.trim())return l;continue}return c}catch(a){if(s=a,a?.response?.status===404)continue;throw a}throw s||new Error("Workspace file not found")}async function Te(n,t,e){let r=We(t,`ws/${e}`),o=r.endsWith("/")?r:`${r}/`,s=[`${o}api/json?depth=1`,`${o}?format=json&depth=1`,`${o}?depth=1&format=json`,`${o}?format=json`,`${o}?depth=1`],i;for(let a of s)try{let l=(await n.axios.get(a,{headers:{Accept:"application/json"}})).data;if(typeof l=="string")try{l=JSON.parse(l);}catch{continue}if(l&&typeof l=="object")return l}catch(c){if(i=c,c?.response?.status===404)continue;throw c}try{let a=await n.axios.get(o,{headers:{Accept:"text/html"}});if(typeof a.data=="string"){let c=Rn(a.data);if(c.length)return {children:c}}}catch(a){i=a;}throw i||new Error("Workspace listing not found")}function Pn(n){if(Array.isArray(n))return n;let t=[n?.children,n?.files,n?.childs,n?.items,n?.entries,n?.content,n?.tree];for(let e of t){if(Array.isArray(e))return e;if(e&&Array.isArray(e.children))return e.children}return n?.children&&Array.isArray(n.children?.children)?n.children.children:[]}function Oe(n){return Pn(n).map(e=>{let r=String(e?.name??e?.displayName??"").trim(),o=String(e?.path??e?.relativePath??e?.filePath??e?.href??e?.url??"").trim(),s=o?o.split("/").filter(Boolean).pop()??o:"",i=r||s||"-",a=o||r||i,c=(()=>e?.directory===!0||e?.isDirectory===!0||e?.isFolder===!0||e?.type==="directory"||e?.type==="dir"||e?.kind==="directory"||e?.kind==="dir"?"dir":e?.file===!0||e?.type==="file"||e?.kind==="file"?"file":"unknown")(),l=X(e?.size)??X(e?.length)??X(e?.fileSize)??X(e?.bytes)??void 0,u=Z(e?.lastModified)??Z(e?.modified)??Z(e?.mtime)??Z(e?.timestamp)??void 0,m=String(e?.href??e?.url??e?.link??"").trim()||void 0;return {name:i,path:a,url:m,size:l,modified:u,type:c}})}function mt(n){let t=n.match(/^(https?):\/\/([^:]+):([^@]+)@(.+)$/);if(!t)throw new p("Invalid apiToken format.",{hint:"Expected: http(s)://username:token@host:port",example:"http://user:token@jenkins.example.com:8080"});let[,e,r,o,s]=t,i=`${e}://${s.replace(/\/$/,"")}/`,a=Sn.create({baseURL:i,auth:{username:r,password:o},proxy:!1,timeout:3e4});return process.argv.includes("--debug")&&a.interceptors.request.use(l=>{let u=String(l.method??"get").toUpperCase(),m=new URL(String(l.url??""),l.baseURL??i).toString(),f=l.params,d=l.data;d instanceof URLSearchParams?d=Object.fromEntries(d):typeof d=="string"?String(l.headers?.["Content-Type"]??l.headers?.["content-type"]??"").includes("application/x-www-form-urlencoded")?d=Object.fromEntries(new URLSearchParams(d)):d=d.trim()?d:void 0:Buffer.isBuffer(d)&&(d=`[Buffer ${d.length} bytes]`);let g={method:u,url:m};return f&&Object.keys(f).length>0&&(g.params=f),d!=null&&d!==""&&(g.data=d),console.log(y.cyan("[Jenkins Debug] Request")),console.log(JSON.stringify(g,null,2)),l}),{baseURL:i,auth:{username:r,password:o},axios:a,crumbForm:void 0}}async function ft(n,t=5e3){try{let e=await n.axios.get("crumbIssuer/api/json",{timeout:t}),{data:r}=e;r?.crumbRequestField&&r?.crumb&&(n.axios.defaults.headers.common[r.crumbRequestField]=r.crumb,n.crumbForm={field:r.crumbRequestField,value:r.crumb});let o=e.headers["set-cookie"];if(o){let s=Array.isArray(o)?o.map(i=>i.split(";")[0].trim()):[String(o).split(";")[0].trim()];n.axios.defaults.headers.common.Cookie=s.join("; ");}}catch{}}function Ve(n){return n.crumbPromise||(n.crumbPromise=ft(n,5e3)),n.crumbPromise}async function W(n){await Ve(n),n.crumbForm||(n.crumbPromise=ft(n,15e3),await n.crumbPromise);}async function H(n,t){let r=(await n.axios.get("queue/api/json?tree=items[id,task[name],actions[parameters[name,value]],why]")).data.items;if(t){let o=t.trim(),s=o.split("/").filter(Boolean).pop();return r.filter(i=>{let a=i.task?.name;return a===o||(s?a===s:!1)})}return r}async function ee(n,t){let e=await n.axios.get(`${x(t)}/api/json?tree=builds[number,url,building,result,timestamp,duration,estimatedDuration,actions[parameters[name,value]]]`);return (Array.isArray(e.data?.builds)?e.data.builds:[]).filter(o=>o?.building).map(o=>({...o,parameters:pe(o.actions)}))}async function de(n){let t=await n.axios.get("computer/api/json?tree=computer[displayName,executors[currentExecutable[number,url]],oneOffExecutors[currentExecutable[number,url]]]"),e=Array.isArray(t.data?.computer)?t.data.computer:[],r=[];for(let i of e){let a=Array.isArray(i?.executors)?i.executors:[],c=Array.isArray(i?.oneOffExecutors)?i.oneOffExecutors:[];for(let l of [...a,...c]){let u=l?.currentExecutable;u?.url&&r.push({number:Number(u.number),url:String(u.url)});}}let o=new Map;for(let i of r)i.url&&o.set(i.url,i);return (await Promise.all([...o.values()].map(async i=>{let a=await vn(n,i.url),c=lt(String(a?.url??i.url));return {...a,job:c}}))).filter(i=>i?.building)}async function te(n,t){return await W(n),await n.axios.post("queue/cancelItem",new URLSearchParams({id:t.toString()}),B),!0}async function ne(n,t,e){try{await W(n),await n.axios.post(`${x(t)}/${e}/stop/`,new URLSearchParams({}),B);}catch(r){let o=r.response?.status;if(o===403){let s=typeof r.response?.data=="string"?r.response.data.slice(0,200):JSON.stringify(r.response?.data??"").slice(0,200),i=/crumb|csrf/i.test(s);console.log(y.red("[Error] 403 Forbidden: Jenkins refused the stop request (likely permissions or CSRF).")),console.log(y.yellow('[Hint] Confirm the current user has "Job" -> "Cancel" permission on this job.')),console.log(i?"[Hint] Jenkins returned a crumb/CSRF error. Ensure crumb + session cookie are sent, or use API token (not password).":s?`[Hint] Jenkins response: ${s}`:'[Hint] If "Job/Cancel" is already granted, also try granting "Run" -> "Update" (some versions use it for stop).');return}if(o===404||o===400||o===500){console.log(`[Info] Build #${e} could not be stopped (HTTP ${o}). Assuming it finished.`);return}throw r}}async function Ie(n,t,e){await W(n);let r=`view/${encodeURIComponent(t)}/addJobToView`;try{await n.axios.post(r,new URLSearchParams({name:e}),B);}catch(o){let s=o?.response?.status;throw s===404?new p(`View not found: ${t}`,{hint:'Check the view name using "jenkins-cli view list".'}):s===400?new p(`Job not found: ${e}`,{hint:'Check the job name using "jenkins-cli job list".'}):o}}async function qe(n,t,e){await W(n);let r=`view/${encodeURIComponent(t)}/removeJobFromView`;try{await n.axios.post(r,new URLSearchParams({name:e}),B);}catch(o){let s=o?.response?.status;throw s===404?new p(`View not found: ${t}`,{hint:'Check the view name using "jenkins-cli view list".'}):s===400?new p(`Job not found: ${e}`,{hint:'Check the job name using "jenkins-cli job list".'}):o}}async function pt(n,t){await W(n);let e=new URLSearchParams({name:t,mode:"hudson.model.ListView",json:JSON.stringify({name:t,mode:"hudson.model.ListView"})});try{await n.axios.post("createView",e,B);}catch(r){let o=r?.response?.status;throw o===400?new p(`View already exists: ${t}`,{hint:'Use "jenkins-cli view list" to see existing views.'}):o===403?new p(`Forbidden to create view: ${t}`,{hint:'Check Jenkins permissions for "Overall/Manage" or "View/Create".'}):r}}async function dt(n,t){await W(n);let e=`view/${encodeURIComponent(t)}/doDelete`;try{await n.axios.post(e,new URLSearchParams({}),B);}catch(r){let o=r?.response?.status;throw o===404?new p(`View not found: ${t}`,{hint:'Check the view name using "jenkins-cli view list".'}):o===403?new p(`Forbidden to delete view: ${t}`,{hint:'Check Jenkins permissions for "Overall/Manage" or "View/Delete".'}):r}}async function ge(n,t,e){let r="branch",o="mode",s=e[o];s&&console.log(`Checking for conflicting builds for mode: ${s}...`);let[i,a]=await Promise.all([H(n,t),ee(n,t)]),c=(m,f)=>{let d=m.actions?.find(b=>b.parameters);return d?d.parameters.find(b=>b.name===f)?.value:void 0},l=e[r];if(s&&l){let m=i.find(f=>c(f,o)===s&&c(f,r)===l);if(m)return new URL(`queue/item/${m.id}/`,n.baseURL).toString()}let u=!1;if(s)for(let m of a)c(m,o)===s&&(console.log(`Stopping running build #${m.number} (mode=${s})...`),await ne(n,t,m.number),u=!0);u&&await new Promise(m=>setTimeout(m,1e3));try{return await W(n),(await n.axios.post(`${x(t)}/buildWithParameters/`,new URLSearchParams({...e}),B)).headers.location||""}catch(m){let f=m?.response?.status,d=ut(m?.response?.data);if(f===400){let g=d?`Jenkins response (snippet):
|
|
31
|
-
${
|
|
32
|
-
${
|
|
33
|
-
${o}`:void 0})}throw e}}async function
|
|
29
|
+
- dev`});return {...r,projectRoot:t}}var U={maxRedirects:0,validateStatus:n=>n>=200&&n<400};function x(n){return `job/${n.split("/").map(e=>e.trim()).filter(Boolean).map(encodeURIComponent).join("/job/")}`}function he(n){let t=Array.isArray(n)?n.find(o=>o?.parameters):void 0,e=Array.isArray(t?.parameters)?t.parameters:[],r={};for(let o of e)o?.name&&(r[String(o.name)]=o?.value);return r}function Oe(n){try{let e=new URL(n).pathname.split("/").filter(Boolean),r=[];for(let o=0;o<e.length-1;o++)e[o]==="job"&&e[o+1]&&r.push(decodeURIComponent(e[o+1]));return r.join("/")}catch{return ""}}async function An(n,t){let r=(await n.axios.get(new URL("api/json?tree=number,url,building,result,timestamp,duration,estimatedDuration,fullDisplayName,displayName,actions[parameters[name,value]]",t).toString())).data??{};return {...r,parameters:he(r.actions)}}function pt(n,t=400){try{let r=(typeof n=="string"?n:JSON.stringify(n??"",null,2)).trim();return r?r.length>t?`${r.slice(0,t)}...`:r:""}catch{return ""}}function ee(n){if(typeof n=="number"&&Number.isFinite(n))return n;if(typeof n=="string"){let t=Number(n);if(Number.isFinite(t))return t}}function te(n){let t=ee(n);if(t!==void 0)return t;if(typeof n=="string"){let e=Date.parse(n);if(!Number.isNaN(e))return e}}function E(n){return n.split("/").map(e=>e.trim()).filter(Boolean).map(encodeURIComponent).join("/")}function Ve(n,t){let e=n.replace(/\/+$/,""),r=t.replace(/^\/+/,"");return /^https?:\/\//i.test(e)?new URL(`${r}`,`${e}/`).toString():`${e}/${r}`}function Q(n){return n.replace(/ /g," ").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'")}function we(n){return n.replace(/<[^>]*>/g,"")}function Fn(n){return /<!doctype\s+html|<html\b|<body\b/i.test(n)}function Bn(n){let t=n.match(/<pre[^>]*>([\s\S]*?)<\/pre>/i),e=n.match(/<code[^>]*>([\s\S]*?)<\/code>/i),r=n.match(/<body[^>]*>([\s\S]*?)<\/body>/i),s=(t?.[1]??e?.[1]??r?.[1]??n).replace(/<br\s*\/?>/gi,`
|
|
30
|
+
`);return Q(we(s))}function Wn(n){let t=[...n.matchAll(/<tr[^>]*>([\s\S]*?)<\/tr>/gi)],e=[],r=new Set;for(let s of t){let i=s[1]??"",a=[...i.matchAll(/<a[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/gi)],c="",l="";for(let v of a){let O=v[1]??"",P=Q(we(v[2]??"")).trim();if(!(!P||P==="..")&&!/all\s+files\s+in\s+zip/i.test(P)){c=O,l=P;break}}if(!c||!l||c==="../"||c==="..")continue;let u=/class="[^"]*folder[^"]*"/i.test(i)||c.endsWith("/")?"dir":"file",p=Q(c.split("?")[0]??"").replace(/\/+$/,"")||l,m=i.match(/class="last-modified"[^>]*>([\s\S]*?)<\/td>/i),f=m?Q(we(m[1]??"")).trim():"",d=f?te(f):void 0,b=`${l}|${p}`;r.has(b)||(r.add(b),e.push({name:l,path:p,type:u,modified:d}));}if(e.length)return e;let o=[...n.matchAll(/<a[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/gi)];for(let s of o){let i=String(s[1]??"").trim(),a=Q(we(s[2]??"")).trim();if(!a||a===".."||/all\s+files\s+in\s+zip/i.test(a)||!i||i==="../"||i===".."||/^https?:\/\//i.test(i)||i.startsWith("/")||i.startsWith("?")||i.startsWith("#")||/\/job\//i.test(i)||/\/view\//i.test(i))continue;let c=i.endsWith("/")?"dir":"file",l=Q(i.split("?")[0]??"").replace(/\/+$/,"")||a,u=`${a}|${l}`;r.has(u)||(r.add(u),e.push({name:a,path:l,type:c}));}return e}async function Ie(n,t,e){let r=Ve(t,`ws/${e}`),o=[`${r}?format=raw`,`${r}?format=txt`,`${r}?format=plain`,`${r}?plain=1`,`${r}?raw=1`,r],s;for(let i of o)try{let a=await n.axios.get(i,{responseType:"arraybuffer",headers:{Accept:"*/*"}}),c=a.data??new ArrayBuffer(0),l=Buffer.from(c);if(!l.length)continue;let u=a.headers?.["content-type"];return {data:l,contentType:u?String(u):void 0}}catch(a){if(s=a,a?.response?.status===404)continue;throw a}throw s||new Error("Workspace file not found")}async function qe(n,t,e){let r=Ve(t,`ws/${e}`),o=[`${r}?format=raw`,`${r}?format=txt`,`${r}?format=plain`,`${r}?plain=1`,`${r}?raw=1`,r],s;for(let i of o)try{let a=await n.axios.get(i,{responseType:"text",headers:{Accept:"text/plain,*/*"}}),c=typeof a.data=="string"?a.data:String(a.data??"");if(!c)continue;if(Fn(c)){let l=Bn(c);if(l.trim())return l;continue}return c}catch(a){if(s=a,a?.response?.status===404)continue;throw a}throw s||new Error("Workspace file not found")}async function De(n,t,e){let r=Ve(t,`ws/${e}`),o=r.endsWith("/")?r:`${r}/`,s=[`${o}api/json?depth=1`,`${o}?format=json&depth=1`,`${o}?depth=1&format=json`,`${o}?format=json`,`${o}?depth=1`],i;for(let a of s)try{let l=(await n.axios.get(a,{headers:{Accept:"application/json"}})).data;if(typeof l=="string")try{l=JSON.parse(l);}catch{continue}if(l&&typeof l=="object")return l}catch(c){if(i=c,c?.response?.status===404)continue;throw c}try{let a=await n.axios.get(o,{headers:{Accept:"text/html"}});if(typeof a.data=="string"){let c=Wn(a.data);if(c.length)return {children:c}}}catch(a){i=a;}throw i||new Error("Workspace listing not found")}function Un(n){if(Array.isArray(n))return n;let t=[n?.children,n?.files,n?.childs,n?.items,n?.entries,n?.content,n?.tree];for(let e of t){if(Array.isArray(e))return e;if(e&&Array.isArray(e.children))return e.children}return n?.children&&Array.isArray(n.children?.children)?n.children.children:[]}function Me(n){return Un(n).map(e=>{let r=String(e?.name??e?.displayName??"").trim(),o=String(e?.path??e?.relativePath??e?.filePath??e?.href??e?.url??"").trim(),s=o?o.split("/").filter(Boolean).pop()??o:"",i=r||s||"-",a=o||r||i,c=(()=>e?.directory===!0||e?.isDirectory===!0||e?.isFolder===!0||e?.type==="directory"||e?.type==="dir"||e?.kind==="directory"||e?.kind==="dir"?"dir":e?.file===!0||e?.type==="file"||e?.kind==="file"?"file":"unknown")(),l=ee(e?.size)??ee(e?.length)??ee(e?.fileSize)??ee(e?.bytes)??void 0,u=te(e?.lastModified)??te(e?.modified)??te(e?.mtime)??te(e?.timestamp)??void 0,p=String(e?.href??e?.url??e?.link??"").trim()||void 0;return {name:i,path:a,url:p,size:l,modified:u,type:c}})}function ft(n){let t=n.match(/^(https?):\/\/([^:]+):([^@]+)@(.+)$/);if(!t)throw new g("Invalid apiToken format.",{hint:"Expected: http(s)://username:token@host:port",example:"http://user:token@jenkins.example.com:8080"});let[,e,r,o,s]=t,i=`${e}://${s.replace(/\/$/,"")}/`,a=En.create({baseURL:i,auth:{username:r,password:o},proxy:!1,timeout:3e4});return process.argv.includes("--debug")&&a.interceptors.request.use(l=>{let u=String(l.method??"get").toUpperCase(),p=new URL(String(l.url??""),l.baseURL??i).toString(),m=l.params,f=l.data;f instanceof URLSearchParams?f=Object.fromEntries(f):typeof f=="string"?String(l.headers?.["Content-Type"]??l.headers?.["content-type"]??"").includes("application/x-www-form-urlencoded")?f=Object.fromEntries(new URLSearchParams(f)):f=f.trim()?f:void 0:Buffer.isBuffer(f)&&(f=`[Buffer ${f.length} bytes]`);let d={method:u,url:p};return m&&Object.keys(m).length>0&&(d.params=m),f!=null&&f!==""&&(d.data=f),console.log(y.cyan("[Jenkins Debug] Request")),console.log(JSON.stringify(d,null,2)),l}),{baseURL:i,auth:{username:r,password:o},axios:a,crumbForm:void 0}}async function dt(n,t=5e3){try{let e=await n.axios.get("crumbIssuer/api/json",{timeout:t}),{data:r}=e;r?.crumbRequestField&&r?.crumb&&(n.axios.defaults.headers.common[r.crumbRequestField]=r.crumb,n.crumbForm={field:r.crumbRequestField,value:r.crumb});let o=e.headers["set-cookie"];if(o){let s=Array.isArray(o)?o.map(i=>i.split(";")[0].trim()):[String(o).split(";")[0].trim()];n.axios.defaults.headers.common.Cookie=s.join("; ");}}catch{}}function ze(n){return n.crumbPromise||(n.crumbPromise=dt(n,5e3)),n.crumbPromise}async function L(n){await ze(n),n.crumbForm||(n.crumbPromise=dt(n,15e3),await n.crumbPromise);}async function G(n,t){let r=(await n.axios.get("queue/api/json?tree=items[id,task[name],actions[parameters[name,value]],why]")).data.items;if(t){let o=t.trim(),s=o.split("/").filter(Boolean).pop();return r.filter(i=>{let a=i.task?.name;return a===o||(s?a===s:!1)})}return r}async function ne(n,t){let e=await n.axios.get(`${x(t)}/api/json?tree=builds[number,url,building,result,timestamp,duration,estimatedDuration,actions[parameters[name,value]]]`);return (Array.isArray(e.data?.builds)?e.data.builds:[]).filter(o=>o?.building).map(o=>({...o,parameters:he(o.actions)}))}async function be(n){let t=await n.axios.get("computer/api/json?tree=computer[displayName,executors[currentExecutable[number,url]],oneOffExecutors[currentExecutable[number,url]]]"),e=Array.isArray(t.data?.computer)?t.data.computer:[],r=[];for(let i of e){let a=Array.isArray(i?.executors)?i.executors:[],c=Array.isArray(i?.oneOffExecutors)?i.oneOffExecutors:[];for(let l of [...a,...c]){let u=l?.currentExecutable;u?.url&&r.push({number:Number(u.number),url:String(u.url)});}}let o=new Map;for(let i of r)i.url&&o.set(i.url,i);return (await Promise.all([...o.values()].map(async i=>{let a=await An(n,i.url),c=Oe(String(a?.url??i.url));return {...a,job:c}}))).filter(i=>i?.building)}async function re(n,t){return await L(n),await n.axios.post("queue/cancelItem",new URLSearchParams({id:t.toString()}),U),!0}async function oe(n,t,e){try{await L(n),await n.axios.post(`${x(t)}/${e}/stop/`,new URLSearchParams({}),U);}catch(r){let o=r.response?.status;if(o===403){let s=typeof r.response?.data=="string"?r.response.data.slice(0,200):JSON.stringify(r.response?.data??"").slice(0,200),i=/crumb|csrf/i.test(s);console.log(y.red("[Error] 403 Forbidden: Jenkins refused the stop request (likely permissions or CSRF).")),console.log(y.yellow('[Hint] Confirm the current user has "Job" -> "Cancel" permission on this job.')),console.log(i?"[Hint] Jenkins returned a crumb/CSRF error. Ensure crumb + session cookie are sent, or use API token (not password).":s?`[Hint] Jenkins response: ${s}`:'[Hint] If "Job/Cancel" is already granted, also try granting "Run" -> "Update" (some versions use it for stop).');return}if(o===404||o===400||o===500){console.log(`[Info] Build #${e} could not be stopped (HTTP ${o}). Assuming it finished.`);return}throw r}}async function _e(n,t,e){await L(n);let r=`view/${encodeURIComponent(t)}/addJobToView`;try{await n.axios.post(r,new URLSearchParams({name:e}),U);}catch(o){let s=o?.response?.status;throw s===404?new g(`View not found: ${t}`,{hint:'Check the view name using "jenkins-cli view list".'}):s===400?new g(`Job not found: ${e}`,{hint:'Check the job name using "jenkins-cli job list".'}):o}}async function He(n,t,e){await L(n);let r=`view/${encodeURIComponent(t)}/removeJobFromView`;try{await n.axios.post(r,new URLSearchParams({name:e}),U);}catch(o){let s=o?.response?.status;throw s===404?new g(`View not found: ${t}`,{hint:'Check the view name using "jenkins-cli view list".'}):s===400?new g(`Job not found: ${e}`,{hint:'Check the job name using "jenkins-cli job list".'}):o}}async function gt(n,t){await L(n);let e=new URLSearchParams({name:t,mode:"hudson.model.ListView",json:JSON.stringify({name:t,mode:"hudson.model.ListView"})});try{await n.axios.post("createView",e,U);}catch(r){let o=r?.response?.status;throw o===400?new g(`View already exists: ${t}`,{hint:'Use "jenkins-cli view list" to see existing views.'}):o===403?new g(`Forbidden to create view: ${t}`,{hint:'Check Jenkins permissions for "Overall/Manage" or "View/Create".'}):r}}async function wt(n,t){await L(n);let e=`view/${encodeURIComponent(t)}/doDelete`;try{await n.axios.post(e,new URLSearchParams({}),U);}catch(r){let o=r?.response?.status;throw o===404?new g(`View not found: ${t}`,{hint:'Check the view name using "jenkins-cli view list".'}):o===403?new g(`Forbidden to delete view: ${t}`,{hint:'Check Jenkins permissions for "Overall/Manage" or "View/Delete".'}):r}}async function ye(n,t,e){let r="branch",o="mode",s=e[o];s&&console.log(`Checking for conflicting builds for mode: ${s}...`);let[i,a]=await Promise.all([G(n,t),ne(n,t)]),c=(p,m)=>{let f=p.actions?.find(b=>b.parameters);return f?f.parameters.find(b=>b.name===m)?.value:void 0},l=e[r];if(s&&l){let p=i.find(m=>c(m,o)===s&&c(m,r)===l);if(p)return new URL(`queue/item/${p.id}/`,n.baseURL).toString()}let u=!1;if(s)for(let p of a)c(p,o)===s&&(console.log(`Stopping running build #${p.number} (mode=${s})...`),await oe(n,t,p.number),u=!0);u&&await new Promise(p=>setTimeout(p,1e3));try{return await L(n),(await n.axios.post(`${x(t)}/buildWithParameters/`,new URLSearchParams({...e}),U)).headers.location||""}catch(p){let m=p?.response?.status,f=pt(p?.response?.data);if(m===400){let d=f?`Jenkins response (snippet):
|
|
31
|
+
${f}`:void 0;throw new g("Jenkins rejected the request (400).",{hint:`Common causes: job is not parameterized, parameter names do not match, or the job endpoint differs (e.g. multibranch jobs). This CLI sends parameters "${r}" and "${o}".`,example:"jenkins-cli build -b origin/main -m dev",details:d})}if(m){let d=f?`Jenkins response (snippet):
|
|
32
|
+
${f}`:void 0;throw new g(`Request failed with status code ${m}.`,{hint:"Check Jenkins job permissions and parameters.",example:"jenkins-cli me",details:d})}throw p}}async function ht(n){return (await n.axios.get("whoAmI/api/json")).data}async function V(n){return (await n.axios.get("api/json?tree=jobs[name,url,color]")).data.jobs??[]}async function ie(n){let t="plugins[shortName,longName,version,enabled,active,hasUpdate,pinned,bundled,deleted]";return (await n.axios.get(`pluginManager/api/json?tree=${t}`)).data.plugins??[]}async function bt(n){let t=await n.axios.get("config.xml",{responseType:"text"});return String(t.data??"")}async function yt(n){let t=await n.axios.get("credentials/store/system/domain/_/config.xml",{responseType:"text"});return String(t.data??"")}async function kt(n){return (await n.axios.get("credentials/store/system/domain/_/api/json?tree=credentials[id,displayName,description,typeName]")).data??{}}function Ln(n){let t="jobs[name,url]";for(let e=0;e<n;e+=1)t=`jobs[name,url,${t}]`;return t}async function xt(n,t){let e=Math.max(1,t?.depth??8),r=Ln(e),o=await n.axios.get(`api/json?tree=${encodeURIComponent(r)}`),s=Array.isArray(o.data?.jobs)?o.data.jobs:[],i=new Set,a=[...s];for(;a.length;){let c=a.shift();if(!c)continue;let l=String(c.name??"").trim(),u=String(c.url??"").trim();if(l&&u){let p=Oe(u);p?i.add(p):i.add(l);}Array.isArray(c.jobs)&&a.push(...c.jobs);}return [...i].sort((c,l)=>c.localeCompare(l,"en",{sensitivity:"base"}))}async function jt(n,t,e){let r=String(t??"").trim();if(!r)return;let o=Math.max(1,e?.depth??5),s="jobs[name,url]";for(let u=0;u<o;u+=1)s=`jobs[name,url,${s}]`;let i=await n.axios.get(`api/json?tree=${encodeURIComponent(s)}`),a=Array.isArray(i.data?.jobs)?i.data.jobs:[],c=[],l=[...a];for(;l.length;){let u=l.shift();if(!u)continue;let p=String(u.name??"").trim();if(p&&p===r&&u.url){let m=Oe(String(u.url));m&&c.push(m);}Array.isArray(u.jobs)&&l.push(...u.jobs);}if(c.length)return c[0]}async function ke(n,t){try{let r=(await n.axios.get(`${x(t)}/api/json?tree=name,fullName,url,buildable,inQueue,nextBuildNumber,color,healthReport[description,score],lastBuild[number,url,building,result,timestamp,duration],lastCompletedBuild[number,url,result,timestamp,duration],lastSuccessfulBuild[number,url,building,result,timestamp,duration],lastFailedBuild[number,url,building,result,timestamp,duration]`)).data??{},o=typeof r?.fullName=="string"?r.fullName:"",s=typeof r?.name=="string"?r.name:"",i=String(t??"").trim();if(!o&&!s)throw new g(`Job not found: ${i}`,{hint:"Check the job name or use -j/--job to specify the correct job.",example:"jenkins-cli job show -j my-job"});if(i&&i!==o&&i!==s)throw new g(`Job not found: ${i}`,{hint:`Jenkins returned job "${o||s}".`,example:"jenkins-cli console last -j my-job -s success"});return r}catch(e){if(e?.response?.status===404){let o=String(t??"").trim();throw new g(`Job not found: ${o}`,{hint:"Check the job name or use -j/--job to specify the correct job.",example:"jenkins-cli console last -j my-job -s success"})}throw e}}async function Ct(n,t,e){let r=Math.max(1,e?.limit??20);return ((await n.axios.get(`${x(t)}/api/json?tree=builds[number,url,building,result,timestamp,duration,actions[parameters[name,value]]]{0,${r}}`)).data.builds??[]).map(i=>({number:i.number,result:i.result,building:i.building,timestamp:i.timestamp,duration:i.duration,url:i.url,parameters:he(i.actions)}))}async function St(n,t,e){let r=Math.max(1,e?.limit??20);return ((await n.axios.get(`${x(t)}/api/json?tree=builds[number,url,timestamp,changeSet[items[msg,author[fullName,id,absoluteUrl],authorEmail,authorId,date]]]{0,${r}}`)).data.builds??[]).map(i=>({number:i.number,timestamp:i.timestamp,url:i.url,changeSet:i.changeSet??{}}))}async function xe(n,t,e){let o=(await n.axios.get(`${x(t)}/${e}/api/json?tree=number,url,building,result,timestamp,duration,estimatedDuration,fullDisplayName,displayName,description,actions[parameters[name,value]],changeSet[items[msg,author[fullName,id,absoluteUrl],authorEmail,authorId,date]],culprits[fullName],executor[number,progress]`)).data??{};return {...o,parameters:he(o.actions)}}async function vt(n,t,e){let r=await n.axios.get(`${x(t)}/${e}/consoleText`,{responseType:"text"});return String(r.data??"")}async function $t(n,t){return ((await n.axios.get(`${x(t)}/api/json?tree=property[parameterDefinitions[name,type,description,defaultParameterValue[value],choices]]`)).data?.property??[]).flatMap(s=>s?.parameterDefinitions??[]).filter(Boolean).map(s=>({name:s.name,type:s.type,description:s.description,default:s.defaultParameterValue?.value,choices:s.choices}))}async function Qe(n,t,e){let r=String(e?.path??"").trim(),o=r?`${E(r)}/`:"",s=await De(n,x(t),o);return Me(s??{})}async function Jt(n,t,e,r){let o=String(r?.path??"").trim(),s=o?`${E(o)}/`:"",i=`view/${encodeURIComponent(t)}/${x(e)}`,a=await De(n,i,s);return Me(a??{})}async function Pt(n,t,e,r){let o=String(r?.path??"").trim(),s=o?`${E(o)}/`:"",i=new URL(`${x(e)}/`,t).toString(),a=await De(n,i,s);return Me(a??{})}async function Rt(n,t,e){let r=E(String(e??"").trim());return await qe(n,x(t),r)}async function Nt(n,t,e){let r=E(String(e??"").trim());return await Ie(n,x(t),r)}async function Et(n,t,e,r){let o=E(String(r??"").trim()),s=`view/${encodeURIComponent(t)}/${x(e)}`;return await qe(n,s,o)}async function At(n,t,e,r){let o=E(String(r??"").trim()),s=`view/${encodeURIComponent(t)}/${x(e)}`;return await Ie(n,s,o)}async function Ft(n,t,e,r){let o=E(String(r??"").trim()),s=new URL(`${x(e)}/`,t).toString();return await qe(n,s,o)}async function Bt(n,t,e,r){let o=E(String(r??"").trim()),s=new URL(`${x(e)}/`,t).toString();return await Ie(n,s,o)}async function Wt(n,t){try{return await L(n),await n.axios.post(`${x(t)}/doWipeOutWorkspace`,new URLSearchParams({}),U),!0}catch(e){let r=e?.response?.status;if(r){let o=pt(e?.response?.data);throw new g(`Workspace wipe failed (HTTP ${r}).`,{hint:"Check Job/Workspace permission or CSRF settings.",example:"jenkins-cli workspace wipe -j my-job",details:o?`Jenkins response (snippet):
|
|
33
|
+
${o}`:void 0})}throw e}}async function se(n,t){let e=await n.axios.get(`${x(t)}/config.xml`,{responseType:"text"});return String(e.data??"")}async function Ut(n,t,e,r){let o=`${x(t)}/${e}/logText/progressiveText`,s=new URLSearchParams;s.append("start",String(r));let i=await n.axios.post(o,s,{responseType:"text"}),a=String(i.data??""),c=i.headers["x-text-size"],l=i.headers["x-more-data"],u=c?Number(c):r+Buffer.byteLength(a);return {text:a,newOffset:u,hasMoreData:l==="true"}}async function ae(n,t){let e=t?.raw?"views[*]":"views[name,url]";return (await n.axios.get(`api/json?tree=${e}`)).data.views??[]}async function K(n,t){let e=`view/${encodeURIComponent(t)}`;try{return (await n.axios.get(`${e}/api/json?tree=jobs[name,url,color]`)).data.jobs??[]}catch(r){throw r?.response?.status===404?new g(`View not found: ${t}`,{hint:'Check the view name using "jenkins-cli view list".',example:"jenkins-cli view show MyView"}):r}}async function Lt(n,t){let e=String(t??"").trim();if(!e)return;let r=e.split("/").filter(Boolean).pop()??e,o=await ae(n,{raw:!1});for(let s of o){let i=String(s?.name??"").trim();if(i)try{if((await K(n,i)).some(c=>{let l=String(c?.name??"").trim();return l===e||l===r}))return i}catch{}}}async function h(){let n=un("Loading configuration...").start();try{let t=await mt();n.succeed("Configuration loaded");let e=ft(t.apiToken);return ze(e),{config:t,jenkins:e}}catch(t){M(t),process.exit(1);}}var qn=Vn(fileURLToPath(import.meta.url),{interopDefault:!0});async function Ce(n){return await Promise.resolve(n)}function Dn(n){let t=String(n??"").trim();if(!t)return null;let e=t.lastIndexOf(":");if(e<=0||e===t.length-1)return null;let r=t.slice(0,e).trim(),o=t.slice(e+1).trim();if(!r||!o)return null;let s=r.lastIndexOf(":");if(s>0){let i=r.slice(s+1).trim(),a=r.slice(0,s).trim();i&&a&&!/[\\/]/.test(i)&&(r=a);}return {file:r,exportName:o}}function Mn(n,t){return W.isAbsolute(t)?t:W.join(n,t)}function Vt(n){return !!n&&typeof n=="object"&&!Array.isArray(n)}async function Se(n,t){let e=Dn(t);if(!e)return null;let r=Mn(n,e.file);if(!await _.pathExists(r))throw new g(`configs reference not found: ${e.file}`,{hint:"Check the file path (relative to project root) and file name.",example:'configs: [{ choices: "./scripts/prompts.ts:choices" }]'});let o=qn(r),s=Vt(o)?o:{default:o},i=e.exportName==="default"?s.default:s[e.exportName];if(i===void 0)throw new g(`configs reference export not found: ${t}`,{hint:"Make sure the export exists in the referenced file.",example:'export const choices = ["dev", "uat"]'});return {value:i}}async function It(n,t){if(typeof t!="string")return {isRef:!1,isFunction:!1,value:t};let e=await Se(n,t);return e?{isRef:!0,isFunction:typeof e.value=="function",value:e.value}:{isRef:!1,isFunction:!1,value:t}}async function je(n,t,e){if(typeof t!="string")return t;let r=await Se(n,t);if(!r)return t;if(!e.allow(r.value))throw new g(e.error(t),{hint:e.hint,example:e.example});return r.value}async function Ot(n,t){if(typeof t!="string")return t;let e=await Se(n,t);if(!e)return t;if(typeof e.value=="function"){let r=e.value();return await Ce(r)}return await Ce(e.value)}async function I(n,t,e){if(typeof t!="string")return t;let r=await Se(n,t);if(!r)return t;if(typeof r.value=="function"){let o=r.value(e);return await Ce(o)}return await Ce(r.value)}async function ve(n,t){let e=Array.isArray(n)?n:[];if(e.length===0)return [];let r=String(t.projectRoot??"").trim()||process.cwd(),o=[];for(let s of e){if(!Vt(s))continue;let i={...s};if(i.choices!==void 0){i.choices=await Ot(r,i.choices);let a=String(i.type??"").toLowerCase(),c=i.choices;if((a==="list"||a==="rawlist"||a==="checkbox")&&typeof c!="function"&&!Array.isArray(c))if(c==null)i.choices=[];else if(typeof c=="string"||typeof c=="number"||typeof c=="boolean")i.choices=[String(c)];else if(typeof c[Symbol.iterator]=="function")i.choices=Array.from(c).map(u=>String(u));else throw new g(`configs "${String(i.name??"")}" choices must resolve to an array (got ${typeof c}).`,{hint:"Return an array for list/rawlist/checkbox choices.",example:'export const choices = ["dev", "uat"]'})}i.default!==void 0&&(i.default=await Ot(r,i.default)),i.when!==void 0&&(i.when=await je(r,i.when,{allow:a=>typeof a=="function"||typeof a=="boolean",error:a=>`when reference must be a function or boolean: ${a}`,hint:"Export a function or boolean from the referenced file.",example:'export const when = (answers) => answers.env === "dev"'})),i.validate!==void 0&&(i.validate=await je(r,i.validate,{allow:a=>typeof a=="function",error:a=>`validate reference must be a function: ${a}`,hint:"Export a function from the referenced file.",example:'export const validate = (input) => !!input || "required"'})),i.filter!==void 0&&(i.filter=await je(r,i.filter,{allow:a=>typeof a=="function",error:a=>`filter reference must be a function: ${a}`,hint:"Export a function from the referenced file.",example:"export const filter = (input) => input.trim()"})),i.transformer!==void 0&&(i.transformer=await je(r,i.transformer,{allow:a=>typeof a=="function",error:a=>`transformer reference must be a function: ${a}`,hint:"Export a function from the referenced file.",example:"export const transformer = (input) => input.toUpperCase()"})),o.push(i);}return o}function qt(n,t){let e=new Set(t),r={};for(let[o,s]of Object.entries(n))if(!e.has(o)&&s!==void 0){if(s===null){r[o]="";continue}if(Array.isArray(s)){r[o]=s.map(i=>String(i)).join(",");continue}if(typeof s=="object"){try{r[o]=JSON.stringify(s);}catch{r[o]=String(s);}continue}r[o]=String(s);}return r}async function Dt(n,t,e={}){let r=(t??"").trim();if(r)return r;let o=e.projectRoot??process.cwd(),s=await I(o,n,e.answers??{});return String(s??"").trim()||n}function A(n,t){let e=Number(n);if(!Number.isInteger(e)||e<0)throw new g(`${t} must be a non-negative integer.`,{hint:`Provide a valid ${t}.`,example:`jenkins-cli console ${t==="id"?"123":"last -t 100"}`});return e}function $e(n,t){let e=String(t??"").trim();if(!e)return !0;if(!/[*?]/.test(e))return n.includes(e);let s=`^${e.replace(/[$()*+.?[\\\]^{|}]/g,"\\$&").replace(/\\\*/g,".*").replace(/\\\?/g,".")}$`;try{return new RegExp(s).test(n)}catch{return n.includes(e)}}function Je(n){let t=n,e=t?.name?String(t.name):"",r=t?.code?String(t.code):"",o=t?.message?String(t.message):String(t??"");if(e==="ExitPromptError"||e==="AbortError"||e==="PromptAbortError"||r==="ABORT_ERR")return !0;let s=o.toLowerCase();return s.includes("cancelled")||s.includes("canceled")}async function Mt(){console.log(y.bold.blue(`
|
|
34
34
|
\u{1F680} Jenkins CLI - Jenkins Deployment CLI
|
|
35
|
-
`));let{config:n,jenkins:t}=await
|
|
35
|
+
`));let{config:n,jenkins:t}=await h(),[e,r]=await Promise.all([ct(),at()]),o=()=>{process.exit(130);},s,i=n.job,a={};try{process.prependOnceListener("SIGINT",o);let f=await ve(n.configs,{projectRoot:n.projectRoot}),d=new Set(["branch","modes","mode","triggered_by"]);for(let $ of f){let D=String($?.name??"").trim();if(d.has(D))throw new g(`configs name "${D}" is reserved.`,{hint:"Use another name in your extra prompt config.",example:"name: env"})}let b={type:"list",name:"branch",message:"\u8BF7\u9009\u62E9\u8981\u6253\u5305\u7684\u5206\u652F:",choices:e,default:e.indexOf(r)},v=[],O=[],P=[];for(let $ of f){let D=Number($.offset);if(Number.isFinite(D)&&D<=-2){v.push($);continue}if(D===-1){O.push($);continue}P.push($);}let C={};Object.assign(C,await ce.prompt(v,C)),Object.assign(C,await ce.prompt([b],C)),Object.assign(C,await ce.prompt(O,C));let nt=String(n.projectRoot??"").trim()||process.cwd(),X=await I(nt,n.modes,C),Y=[];if(Array.isArray(X))Y=X.map($=>String($).trim()).filter(Boolean);else if(X!=null){let $=String(X).trim();$&&(Y=[$]);}Y.length===0&&Array.isArray(n.modes)&&(Y=n.modes);let yn={type:"checkbox",name:"modes",message:"\u8BF7\u9009\u62E9\u8981\u6253\u5305\u7684\u73AF\u5883:",choices:Y,validate:$=>$.length===0?"You must select at least one environment":!0};Object.assign(C,await ce.prompt([yn],C)),Object.assign(C,await ce.prompt(P,C)),s={branch:String(C.branch??""),modes:C.modes??[]},a=qt(C,["branch","modes"]);let kn=await I(nt,n.job,C),rt=String(kn??"").trim();rt&&(i=rt);}catch(f){let d=f,b=d?.message?String(d.message):String(d),v=d?.name?String(d.name):"";Je(f)&&process.exit(0),M(new g(`Prompt failed: ${b}`,{hint:v?`Error: ${v}`:""})),process.exit(1);}finally{process.off("SIGINT",o);}console.log();let c=!1,l=()=>{c||(c=!0,console.log());},u=await fe();u&&!("triggered_by"in a)&&(a.triggered_by=u);let m=s.modes.map(async f=>{let d=un(`Triggering build for ${y.yellow(f)}...`).start();try{let b=await ye(t,i,{...a,branch:s.branch,mode:f});l(),d.succeed(`${y.green(f)} - Triggered! Queue: ${b}`);}catch(b){throw l(),d.fail(`${y.red(f)} - ${b.message}`),b}});try{await Promise.all(m);}catch{console.log(y.bold.red(`
|
|
36
36
|
\u274C Some builds failed. Check the output above.
|
|
37
|
-
`)),process.exit(1);}}function
|
|
37
|
+
`)),process.exit(1);}}function zt(n){let t=n.command("queue").description("Operations for the build queue");t.command("list").alias("ls").description("List items waiting in the build queue").option("-j, --job <job>","Show only queue items for the specified job").action(async e=>{let{config:r,jenkins:o}=await h(),s=e.job?await Dt(r.job,e.job,{projectRoot:r.projectRoot}):void 0,i=await G(o,s);console.table((i??[]).map(a=>({id:a.id,job:a.task?.name,why:a.why})));}),t.command("cancel").description("Cancel a queued build item").argument("<id...>","Queue id(s)").action(async e=>{let{jenkins:r}=await h(),o=Array.isArray(e)?e:[String(e??"")],s=await Promise.all(o.map(async a=>{let c=A(String(a),"id");try{return await re(r,c),{id:c,ok:!0}}catch(l){return {id:c,ok:!1,message:String(l?.message??l)}}})),i=s.filter(a=>!a.ok);if(i.length===0){console.log(y.green(`Cancelled ${s.length} queue item(s).`));return}console.log(y.yellow(`Cancelled ${s.length-i.length} item(s), failed ${i.length} item(s).`));for(let a of i)console.log(y.red(`- ${a.id}: ${a.message??"Cancel failed"}`));});}function w(n){return {[_n.inspect.custom]:()=>n}}function T(n,t){return String(n??"").padEnd(t," ")}function j(n){return Math.max(0,...n.map(t=>String(t??"").length))}function S(n,t){return w(T(n,t))}function J(n){let t=String(n??""),e=t.trim();if(!e)return w(y.gray("-"));let r=s=>w(s),o=e.toLowerCase();if(o.startsWith("http://")||o.startsWith("https://"))try{let i=(new URL(e).hostname??"").toLowerCase(),a=i==="localhost"||i==="127.0.0.1"||i==="::1",c=/^10\./.test(i)||/^192\.168\./.test(i)||/^127\./.test(i)||/^172\.(1[6-9]|2\d|3[0-1])\./.test(i);return r(a||c?y.cyanBright(t):y.hex("#4EA1FF")(t))}catch{return r(y.hex("#4EA1FF")(t))}return o.startsWith("ws://")||o.startsWith("wss://")?r(y.cyan(t)):o.startsWith("ssh://")||o.startsWith("git+ssh://")||o.startsWith("git@")?r(y.magenta(t)):o.startsWith("file://")?r(y.yellow(t)):o.startsWith("mailto:")?r(y.green(t)):o.startsWith("javascript:")||o.startsWith("data:")?r(y.red(t)):e.startsWith("/")||e.startsWith("./")||e.startsWith("../")?r(y.cyan(t)):/^[a-z0-9.-]+(?::\d+)?(\/|$)/i.test(e)?r(y.blue(t)):r(t)}function R(n){let t=new Date(n),e=r=>String(r).padStart(2,"0");return `${t.getFullYear()}-${e(t.getMonth()+1)}-${e(t.getDate())} ${e(t.getHours())}:${e(t.getMinutes())}:${e(t.getSeconds())}`}function ue(n,t){if(t===!0)return w(y.cyan("BUILDING"));let e=String(n??"").toUpperCase();return w(e?e==="SUCCESS"?y.green(e):e==="ABORTED"?y.gray(e):e==="FAILURE"?y.red(e):e==="UNSTABLE"?y.yellow(e):e==="NOT_BUILT"?y.gray(e):e:"-")}function me(n){let t=String(n??"");if(!t)return w("-");let e=t.endsWith("_anime"),r=e?t.slice(0,-6):t,o=(()=>{switch(r){case"blue":return e?y.blueBright(t):y.blue(t);case"red":return e?y.redBright(t):y.red(t);case"yellow":return e?y.yellowBright(t):y.yellow(t);case"aborted":return y.gray(t);case"disabled":case"notbuilt":case"grey":case"gray":return y.gray(t);default:return t}})();return w(o)}function _t(n){let t=Number(n);if(!Number.isFinite(t)||t<0)return w("-");if(t<1024)return w(`${t} B`);let e=["KB","MB","GB","TB"],r=t,o=-1;for(;r>=1024&&o<e.length-1;)r/=1024,o+=1;let s=r>=10||o===0?r.toFixed(1):r.toFixed(2);return w(`${s} ${e[o]}`)}var Pe=64;function Qn(n){return n!=null&&typeof n=="object"?n.value??n.name??n:n}function Qt(n){let t=String(n?.toString?.()??"").trim();if(!t)return "";let e=t.indexOf("=>");if(e>=0){let s=t.slice(e+2).trim();return s.startsWith("{")&&s.endsWith("}")&&(s=s.slice(1,-1)),s}let r=t.indexOf("{"),o=t.lastIndexOf("}");return r>=0&&o>r?t.slice(r+1,o):""}function Gt(n){let t=new Set,e,r=/\b(\d+)\b/g;for(;e=r.exec(n);){let s=parseInt(e[1],10);Number.isFinite(s)&&t.add(s);}let o=Array.from(t).sort((s,i)=>s-i);return o.length>Pe?o.slice(0,Pe):o}function Gn(n,t){let e=String(n.type??"").toLowerCase();if(e==="confirm")return [!0,!1];if(e==="number"){let s=n,i=typeof s.min=="number"&&Number.isFinite(s.min)?s.min:null,a=typeof s.max=="number"&&Number.isFinite(s.max)?s.max:null;if(i!=null&&a!=null)return i===a?[i]:i<a?[i,a]:[a,i];if(i!=null)return [i,i+1];if(a!=null)return [a-1,a];if(t){let c=Gt(Qt(t));if(c.length)return c}return [0,1,99,100,101]}let r=Array.isArray(n.choices)?n.choices:null;if(!r?.length)return null;let o=r.map(Qn);if(e==="list"||e==="rawlist")return o;if(e==="checkbox"){let s=[[]];return o.forEach(i=>s.push([i])),o.length<=4&&s.push(o),s}return null}async function Kn(n,t){let e=n.when;if(e===void 0||typeof e=="boolean")return e!==!1;if(typeof e!="function")return !0;try{return !!await Promise.resolve(e(t))}catch{return !0}}async function Xn(n,t,e){let r=await ve(n.configs,{projectRoot:t}),o=[{}];for(let s of r){let i=String(s.name??"").trim();if(!i)continue;let a=Gn(s,e);if(!a?.length||o.length*a.length>Pe)continue;let c=[];for(let l of o){if(!await Kn(s,l)){c.push(l);continue}for(let u of a)c.push({...l,[i]:u});}c.length&&(o=c);}return o}function Yn(n){let t=new Map,e=/answers\.(\w+)\s*===\s*(\d+)/g,r;for(;r=e.exec(n);){let s=r[1],i=parseInt(r[2],10);Number.isFinite(i)&&(t.has(s)||t.set(s,new Set),t.get(s).add(i));}let o=new Map;return t.forEach((s,i)=>o.set(i,Array.from(s).sort((a,c)=>a-c))),o}function Zn(n){return n.split(`
|
|
38
38
|
`).filter(t=>{let e=t.trim();return e&&!e.startsWith("//")}).join(`
|
|
39
|
-
`)}function
|
|
40
|
-
--- Build Finished: ${
|
|
39
|
+
`)}function er(n){let t=Qt(n);if(!t)return [];t=Zn(t);let e=Gt(t),r=Yn(t),o=new Set,s=/return\s+([^;]+?)(?=;|$)/gm,i=/`((?:[^`\\]|\\.|\$\{[^}]*\})*)`/g,a=/\$\{\s*answers\.(\w+)\s*\}/,c;for(;c=s.exec(t);){let l=c[1];for(let p of Ht(l))p&&o.add(p);let u;for(;u=i.exec(l);){let p=u[1];if(!p.includes("${"))continue;let m=p.match(a),f=m&&r.has(m[1])?r.get(m[1]):m?[]:e,d=p.split(/\$\{[^}]*\}/);if(d.length<2)continue;let b=d[0]??"",v=d.slice(1).join("");for(let O of f){let P=b+String(O)+v;P&&o.add(P);}}}if(o.size===0&&!t.includes("{"))for(let l of Ht(t))l&&o.add(l);return Array.from(o).sort((l,u)=>l.localeCompare(u,"en",{sensitivity:"base"}))}function Ht(n){let t=[],e=/(['"`])((?:\\.|(?!\1).)*)\1/g,r;for(;r=e.exec(n);)if(!(r[1]==="`"&&r[2].includes("${")))try{let o=r[1]==="`"?r[2]:JSON.parse(r[1]+r[2]+r[1]);String(o).trim()&&t.push(String(o).trim());}catch{String(r[2]??"").trim()&&t.push(String(r[2]).trim());}return t}async function tr(n,t,e){let r=new Set;for(let i of er(n))r.add(i);let o=await Xn(t,e,n),s=async i=>{let a=await Promise.resolve(n(i)),c=typeof a=="string"?String(a).trim():"";return c&&r.add(c),r.size>=Pe};if(!o.length)await s({});else for(let i of o)if(await s(i))break;return Array.from(r).sort((i,a)=>i.localeCompare(a,"en",{sensitivity:"base"}))}async function k(n,t){if(t==="")throw new g("Job is required.",{hint:"Provide a job name after -j/--job.",example:"jenkins-cli job info -j my-job"});let e=String(t??"").trim();if(e)return e;let r=String(n.projectRoot??"").trim()||process.cwd(),o=await It(r,n.job);if(o.isRef&&o.isFunction){let i=await tr(o.value,n,r);if(!i.length)throw new g("Job choices not found from config reference.",{hint:"Ensure the job function returns a string (job name).",example:'export function dynamicJob(answers) { return "my-job" }'});if(i.length===1)return i[0];let{job:a}=await ce.prompt([{type:"list",name:"job",message:"\u8BF7\u9009\u62E9\u8981\u64CD\u4F5C\u7684 Job:",choices:i}]);return String(a??"").trim()}let s=await I(r,n.job,{});return String(s??n.job??"").trim()||String(n.job??"")}function Re(n){let t=process.argv,e=0;if(n){let r=t.lastIndexOf(n);r>=0&&(e=r+1);}for(let r=e;r<t.length;r+=1){let o=t[r];if(o==="-j"||o==="--job"){let s=t[r+1];return !s||s.startsWith("-")?"":s}}}function Kt(n){let t=Object.entries(n??{}).filter(([r])=>r);return t.length?(t.sort(([r],[o])=>r.localeCompare(o,"en",{sensitivity:"base"})),t.map(([r,o])=>{if(o===void 0)return `${r}=`;if(o===null)return `${r}=null`;if(typeof o=="string"||typeof o=="number"||typeof o=="boolean")return `${r}=${o}`;try{return `${r}=${JSON.stringify(o)}`}catch{return `${r}=${String(o)}`}}).join(", ")):"-"}function Xt(n){let t=n.command("builds").description("Build operations");t.option("-j, --job <job>","Specify job").option("-n, --limit <n>","Limit","20").action(async e=>{let{config:r,jenkins:o}=await h(),s=e.job??Re("builds")??Re(),i=await k(r,s),c=(await Ct(o,i,{limit:Number(e.limit)})).map(u=>({number:u.number,result:ue(u.result,u.building),building:u.building,"duration(s)":Number((Number(u.duration??0)/1e3).toFixed(3)),date:w(R(Number(u.timestamp??0))),parameters:Kt(u.parameters),url:J(String(u.url??""))})),l=j(c.map(u=>u.parameters));console.table(c.map(u=>({...u,parameters:S(u.parameters,l)})));}),t.command("active").description("List active builds").option("-j, --job <job>","Specify job").option("-a, --all","Query all running builds on Jenkins").action(async e=>{let{config:r,jenkins:o}=await h(),s=e.job??Re("active")??Re("builds"),i=await k(r,s),c=((e.all?await be(o):await ne(o,i))??[]).map(u=>({...e.all?{job:w(String(u.job??""))}:{},number:u.number,date:w(u.timestamp?R(Number(u.timestamp)):"-"),parameters:Kt(u.parameters),url:J(String(u.url??""))})),l=j(c.map(u=>u.parameters));console.table(c.map(u=>({...u,parameters:S(u.parameters,l)})));});}function nr(n){let t=String(n?.authorEmail??"").trim(),e=t?t.split("@")[0]??"":"";return e||t}function Yt(n){let t=[];for(let e of n){let r=Number(e?.number),o=Number.isInteger(r)?`#${r}`:w("-"),s=e?.timestamp?R(Number(e.timestamp)):"-",i=e?.changeSet?.items??[];if(!i.length){t.push({build:o,date:w(s),author:w("-"),message:w("-")});continue}for(let a of i){let c=nr(a),l=String(a?.msg??"").trim();t.push({build:o,date:w(s),author:w(c||"-"),message:w(l||"-")});}}return t}function Zt(n){n.command("changes").description("List build changes").argument("[id]").option("-j, --job <job>","Specify job").option("-n, --limit <n>","Limit","20").option("--raw","Output raw changeSet payload").action(async(t,e)=>{let{config:r,jenkins:o}=await h(),s=await k(r,e.job);if(t){let c=A(t,"id"),l=await xe(o,s,c);if(e.raw){console.log(JSON.stringify({build:l.number,changeSet:l.changeSet??{}},null,2));return}console.table(Yt([l]));return}let i=Math.max(1,A(e.limit,"limit")),a=await St(o,s,{limit:i});if(e.raw){console.log(JSON.stringify(a.map(c=>({build:c.number,changeSet:c.changeSet??{}})),null,2));return}console.table(Yt(a));});}function en(){let n=process.argv,t=n.findIndex(r=>r==="-j"||r==="--job");if(t<0)return;let e=n[t+1];return !e||e.startsWith("-")?"":e}function tn(n){let t=n.command("console").description("Fetch build console log"),e=async(r,o,s,i)=>{if(!i.follow){let l=await vt(r,o,s);process.stdout.write(l);return}let a=0,c=!0;for(console.log(y.blue(`--- Following log for ${o} build #${s} ---`));;)try{let{text:l,newOffset:u,hasMoreData:p}=await Ut(r,o,s,a);if(l.length>0&&(process.stdout.write(l),a=u),c&&l.length>0&&(c=!1),l.length>0&&p)continue;if(!p){let f=(await xe(r,o,s)).result||"UNKNOWN",d=f==="SUCCESS"?y.green:y.red;console.log(d(`
|
|
40
|
+
--- Build Finished: ${f} ---`));break}await new Promise(m=>setTimeout(m,1e3));}catch{await new Promise(l=>setTimeout(l,2e3));}};t.argument("<id>","Build number").option("-j, --job <job>","Specify job").option("--no-follow","Do not follow the build log").action(async(r,o)=>{let{config:s,jenkins:i}=await h(),a=o.job??en();if(a==="")throw new g("Job is required.",{hint:"Provide a job name after -j/--job.",example:"jenkins-cli console 123 -j my-job"});let c=await k(s,a),l=A(r,"id");await e(i,c,l,o);}),t.command("last").description("Fetch the latest build log").option("-j, --job <job>","Specify job").option("-s, --status <status>","success | failed | any","any").option("--no-follow","Do not follow the build log").action(async r=>{let{config:o,jenkins:s}=await h(),i=r.job??en();if(i==="")throw new g("Job is required.",{hint:"Provide a job name after -j/--job.",example:"jenkins-cli console last -j my-job -s success"});let a=await k(o,i),c=String(r.status??"any").toLowerCase();if(!["any","success","failed"].includes(c))throw new g(`Invalid status: ${r.status}.`,{hint:"Use success | failed | any.",example:"jenkins-cli console last -s success"});let l=await ke(s,a),u=c==="success"?l?.lastSuccessfulBuild:c==="failed"?l?.lastFailedBuild:l?.lastBuild,p=Number(u?.number);if(!p){let m=c==="success"?"successful":c==="failed"?"failed":"last";console.log(y.yellow(`No ${m} build found for job: ${a}. Try checking the job name or status filter.`));return}await e(s,a,p,r);});}function nn(n){n.command("stop").description("Clear queued builds and stop running builds").argument("[id]","Build number").option("-j, --job <job>","Specify Jenkins job").option("-a, --all","Cancel queued items for this job and stop all running builds for it").option("-A, --ALL","Cancel all queued items and stop all running builds on Jenkins").action(async(t,e)=>{let{config:r,jenkins:o}=await h(),s=await k(r,e.job);if(e.ALL){let[i,a]=await Promise.all([G(o),be(o)]),c=(i??[]).map(u=>Number(u.id)).filter(u=>!Number.isNaN(u)),l=(a??[]).map(u=>({number:Number(u.number),job:String(u.job??"")})).filter(u=>u.job&&!Number.isNaN(u.number));for(let u of c)await re(o,u);for(let u of l)await oe(o,u.job,u.number);console.log(y.green(`Requested: cancelled ${c.length} queue item(s), stopped ${l.length} running build(s).`));return}if(e.all){let[i,a]=await Promise.all([G(o,s),ne(o,s)]),c=(i??[]).map(u=>Number(u.id)).filter(u=>!Number.isNaN(u)),l=(a??[]).map(u=>Number(u.number)).filter(u=>!Number.isNaN(u));for(let u of c)await re(o,u);for(let u of l)await oe(o,s,u);console.log(y.green(`Requested: cancelled ${c.length} queue item(s), stopped ${l.length} running build(s).`));return}if(!t){console.log(y.red("Missing build id. Provide <id> or use -a/--all."));return}await oe(o,s,A(t,"id")),console.log(y.green("Stop requested"));});}function rn(n){n.command("params").description("Show job parameter definitions").option("-j, --job <job>","Specify job").action(async t=>{let{config:e,jenkins:r}=await h(),o=await k(e,t.job),s=await $t(r,o),i=j(s.map(a=>a?.name));console.table((s??[]).map(a=>({name:S(a?.name??"",i),type:w(String(a?.type??"")),description:w(String(a?.description??"")),default:w(a?.default===void 0?"-":String(a.default)),choices:w(Array.isArray(a?.choices)?a.choices.join(", "):a?.choices??"-")})));});}function on(n){n.command("me").description("Show Jenkins user info for the current token").option("--raw","Print raw response").action(async t=>{let{jenkins:e}=await h(),r=await ht(e);if(t.raw){console.log(r&&typeof r=="object"?JSON.stringify(r,null,2):String(r));return}let o=r&&typeof r=="object"?r:{value:r},s=(u,p)=>{let m=u.length;if(m>=p)return u;let f=p-m,d=Math.floor(f/2),b=f-d;return `${" ".repeat(d)}${u}${" ".repeat(b)}`},i=o.name??o.fullName??o.id??"",a=i==null?"":String(i),c=Math.max(20,a.length),l={};l.name=w(s(a,c));for(let u of Object.keys(o).sort((p,m)=>p.localeCompare(m,"en"))){if(u==="name")continue;let p=o[u],m=u.toLowerCase();if((m==="url"||m.endsWith("url")||m.includes("url"))&&(typeof p=="string"||typeof p=="number")){l[u]=J(String(p));continue}let d=p==null?"":typeof p=="object"?JSON.stringify(p):String(p);l[u]=w(d);}console.table([l]);});}function sn(n){let t=n.command("config").description("Show Jenkins job configuration");t.command("show").description("Show job configuration").option("-j, --job <job>","Specify job").option("-f, --format <format>","Output format: xml or json","xml").action(async e=>{let{config:r,jenkins:o}=await h(),s=await k(r,e.job),i=String(e.format??"xml").toLowerCase();if(i!=="xml"&&i!=="json")throw new g(`Invalid format: ${e.format}.`,{hint:"Use xml or json.",example:"jenkins-cli config show -f json"});let a=await se(o,s);if(i==="xml"){process.stdout.write(a);return}let l=new XMLParser({ignoreAttributes:!1,attributeNamePrefix:"@_"}).parse(a);console.log(JSON.stringify(l,null,2));}),t.command("backup").description("Backup job configuration to files").requiredOption("-d, --destination <path>","Destination folder").option("-a, --all","Backup all jobs").option("-j, --job <job>","Specify job").option("--filter <pattern>","Filter jobs by name (supports glob)").action(async e=>{let{config:r,jenkins:o}=await h(),s=String(e.destination??"").trim();if(!s)throw new g("Destination is required.",{hint:"Provide a destination folder with -d or --destination.",example:"jenkins-cli config backup -d ./jenkins-backup"});if(e.all&&e.filter)throw new g("Options --all and --filter are mutually exclusive.",{hint:"Use either -a/--all or --filter, not both.",example:"jenkins-cli config backup -d ./jenkins-backup -a"});let i=String(e.filter??"").trim(),a=e.all?await V(o):i?(await V(o)).filter(l=>$e(String(l.name??""),i)):[{name:await k(r,e.job)}];if(a.length===0)throw new g(`No jobs matched filter: ${i}`,{hint:"Check the pattern or remove --filter to use the default job.",example:"jenkins-cli config backup -d ./jenkins-backup --filter 'remote-*'"});await promises.mkdir(s,{recursive:!0});let c=[];for(let l of a){let u=String(l?.name??"").trim();if(!u)continue;let p=await se(o,u),m=W.join(s,u,"config.xml");await promises.mkdir(W.dirname(m),{recursive:!0}),await promises.writeFile(m,p),c.push(m);}console.log(`Backup completed. ${c.length} file(s) saved to ${W.resolve(s)}`);});}function an(n){let t=n.command("job").description("Job operations");t.command("list").alias("ls").description("List all jobs").option("--search <keyword>","Filter by name (supports glob)").action(async e=>{let{jenkins:r}=await h(),o=await V(r),s=(e.search??"").trim(),i=s?o.filter(l=>$e(String(l.name??""),s)):o;i.sort((l,u)=>String(l?.name??"").localeCompare(String(u?.name??""),"en",{sensitivity:"base"}));let a=j(i.map(l=>l?.name)),c=j(i.map(l=>l?.url));console.table((i??[]).map(l=>({name:S(l.name??"",a),color:me(l.color),url:J(T(l.url??"",c))})));}),t.command("info").description("Show job info").option("-j, --job <job>","Specify job").option("--json","Output raw JSON").action(async e=>{let{config:r,jenkins:o}=await h(),s=await k(r,e.job),i=await ke(o,s);if(e.json){console.log(JSON.stringify(i,null,2));return}let a=i?.lastBuild,c=i?.lastCompletedBuild,l=Array.isArray(i?.healthReport)?i.healthReport:[];console.table([{name:w(String(i?.name??"")),url:J(String(i?.url??"")),color:me(i?.color),buildable:i?.buildable,inQueue:i?.inQueue,nextBuildNumber:i?.nextBuildNumber,healthScore:l[0]?.score??"-",lastBuild:w(a?.number?`#${a.number}`:"-"),lastResult:ue(a?.result,a?.building),"lastDuration(s)":a?.duration===void 0?"-":Number((Number(a.duration)/1e3).toFixed(3)),lastDate:w(a?.timestamp?R(Number(a.timestamp)):"-"),lastCompleted:w(c?.number?`#${c.number}`:"-"),lastCompletedResult:ue(c?.result,!1),lastCompletedDate:w(c?.timestamp?R(Number(c.timestamp)):"-")}]);});}function ir(n){return n.split(",").map(t=>t.trim()).filter(Boolean)}function sr(n){let t=n.split("=");if(t.length<2)throw new g(`Invalid --param: "${n}".`,{hint:"Use the format key=value.",example:"jenkins-cli build -b origin/main -m dev --param foo=bar"});let e=t[0].trim(),r=t.slice(1).join("=").trim();if(!e)throw new g(`Invalid --param: "${n}". Key is empty.`,{hint:'Provide a non-empty key before "=".',example:"jenkins-cli build -b origin/main -m dev --param foo=bar"});return {key:e,value:r}}function cn(n){n.command("build").description("Trigger Jenkins builds non-interactively").requiredOption("-b, --branch <branch>","Branch (e.g., origin/develop)").option("-m, --mode <mode>","Deployment environment (repeatable or comma-separated: -m dev -m uat / -m dev,uat)",(t,e)=>e.concat(ir(t)),[]).option("--param <key=value>","Extra parameters (repeatable, e.g., --param foo=bar)",(t,e)=>e.concat(t),[]).option("-j, --job <job>","Specify job").action(async t=>{let{config:e,jenkins:r}=await h(),o=await k(e,t.job),s=String(t.branch??"").trim();if(!s)throw new g("branch is required.",{hint:"Pass a branch with -b or --branch.",example:"jenkins-cli build -b origin/develop -m dev"});let i=(t.mode??[]).map(String).map(f=>f.trim()).filter(Boolean),a=Array.from(new Set(i));if(a.length===0)throw new g("mode is required.",{hint:"Pass at least one -m/--mode.",example:"jenkins-cli build -b origin/develop -m dev -m uat"});let c={};for(let f of t.param??[]){let{key:d,value:b}=sr(String(f));c[d]=b;}let l=await fe();l&&!("triggered_by"in c)&&(c.triggered_by=l),console.log();let u=!1,p=()=>{u||(u=!0,console.log());},m=a.map(async f=>{let d=un(`Triggering build for ${y.yellow(f)}...`).start();try{let b=await ye(r,o,{...c,branch:s,mode:f});p(),d.succeed(`${y.green(f)} - Triggered! Queue: ${b}`);}catch(b){throw p(),d.fail(`${y.red(f)} - ${b.message}`),b}});try{await Promise.all(m);}catch{console.log(y.bold.red(`
|
|
41
41
|
\u274C Some builds failed. Check the output above.
|
|
42
|
-
`)),process.exit(1);}});}function
|
|
42
|
+
`)),process.exit(1);}});}function ln(n){let t=n.command("view").description("View operations");t.command("list").alias("ls").description("List all views").option("--raw","Output raw JSON").action(async e=>{let{jenkins:r}=await h(),o=await ae(r,{raw:e.raw});if(e.raw){console.log(JSON.stringify(o,null,2));return}o.sort((c,l)=>String(c?.name??"").localeCompare(String(l?.name??""),"en",{sensitivity:"base"}));let s=(o??[]).map(c=>({name:String(c?.name??""),url:String(c?.url??"")})),i=j(s.map(c=>c.name)),a=j(s.map(c=>c.url));console.table(s.map(c=>({name:S(c.name,i),url:J(T(c.url,a))})));}),t.command("show").description("Show jobs in a view").argument("<name>","View name").action(async e=>{let{jenkins:r}=await h(),o=await K(r,e);if(!o.length){console.log("No jobs found in this view.");return}o.sort((a,c)=>String(a?.name??"").localeCompare(String(c?.name??""),"en",{sensitivity:"base"}));let s=j(o.map(a=>a?.name)),i=j(o.map(a=>a?.url));console.table(o.map(a=>({name:S(a.name??"",s),color:me(a.color),url:J(T(a.url??"",i))})));}),t.command("add").description("Add a job to a view").argument("<view>","View name").argument("<job>","Job name").action(async(e,r)=>{let{jenkins:o}=await h();if((await K(o,e)).some(i=>i.name===r)){console.log(y.yellow(`Job "${r}" is already in view "${e}".`));return}await _e(o,e,r),console.log(y.green(`Job "${r}" added to view "${e}".`));}),t.command("remove").alias("rm").description("Remove a job from a view").argument("<view>","View name").argument("<job>","Job name").action(async(e,r)=>{let{jenkins:o}=await h();if(!(await K(o,e)).some(i=>i.name===r))throw new g(`Job "${r}" is not in view "${e}".`,{hint:'Use "jc view show <name>" to see jobs in this view.'});await He(o,e,r),console.log(y.green(`Job "${r}" removed from view "${e}".`));}),t.command("edit").description("Edit jobs in a view").argument("<name>","View name").action(async e=>{let{jenkins:r}=await h(),[o,s]=await Promise.all([V(r),K(r,e)]);if(!o.length){console.log("No jobs found.");return}o.sort((m,f)=>String(m?.name??"").localeCompare(String(f?.name??""),"en",{sensitivity:"base"}));let i=new Set(s.map(m=>String(m?.name??"").trim())),a=o.map(m=>String(m?.name??"").trim()).filter(Boolean).map(m=>({name:m,checked:i.has(m)})),c=await ce.prompt([{type:"checkbox",name:"jobs",message:`Select jobs for view "${e}"`,choices:a,pageSize:20}]),l=new Set((c.jobs??[]).map(m=>String(m).trim())),u=[...l].filter(m=>!i.has(m)),p=[...i].filter(m=>m&&!l.has(m));if(!u.length&&!p.length){console.log(y.yellow("No changes to apply."));return}for(let m of u)await _e(r,e,m);for(let m of p)await He(r,e,m);console.log(y.green(`View "${e}" updated.`));}),t.command("create").description("Create a view").argument("<name>","View name").action(async e=>{let{jenkins:r}=await h();await gt(r,e),console.log(y.green(`View "${e}" created.`));}),t.command("delete").alias("del").description("Delete a view").argument("<name>","View name").action(async e=>{let{jenkins:r}=await h();await wt(r,e),console.log(y.green(`View "${e}" deleted.`));});}function mr(n){return w(n?R(n):"-")}function Be(n){let t=process.argv,e=0;if(n){let r=t.lastIndexOf(n);r>=0&&(e=r+1);}for(let r=e;r<t.length;r+=1){let o=t[r];if(o==="-j"||o==="--job"){let s=t[r+1];return !s||s.startsWith("-")?"":s}}}function Ye(n,t,e){let r=t?.parent?.opts()?.job,o=Be(e)??Be(t?.name())??Be("ws")??Be("workspace");return n??r??o}function mn(n){return n.replace(/^\/+/,"").replace(/\/+$/,"")}function pr(n,t){let e=mn(n),r=mn(t);return e?r?r===e||r.startsWith(`${e}/`)?r:`${e}/${r}`:e:r||""}function fr(n){let t=process.platform,e="",r=[];t==="darwin"?(e="open",r=[n]):t==="win32"?(e="cmd",r=["/c","start","",n]):(e="xdg-open",r=[n]);try{spawn(e,r,{stdio:"ignore",detached:!0}).unref();}catch{}}async function N(n){try{return await n()}catch(t){if(t?.response?.status===404)return null;throw t}}async function dr(n,t){try{return await jt(n,t)}catch{return}}async function gr(n,t){try{return await Lt(n,t)}catch{return}}async function wr(n){try{return await ae(n,{raw:!1})}catch{return []}}async function Ze(n,t,e){let r=await e.direct(t);if(r!==null)return r;let o=await dr(n,t);if(o&&o!==t){let a=await e.direct(o);if(a!==null)return a}if(e.beforeView){let a=await e.beforeView();if(a!==null)return a}let s=await gr(n,t);if(s){let a=await e.byViewName(s);if(a!==null)return a}let i=await wr(n);for(let a of i){let c=String(a?.url??"").trim();if(!c)continue;let l=await e.byViewUrl(c);if(l!==null)return l}return null}async function hr(n,t,e){return await Ze(n,t,{direct:r=>N(()=>Qe(n,r,{path:e})),byViewName:r=>N(()=>Jt(n,r,t,{path:e})),byViewUrl:r=>N(()=>Pt(n,r,t,{path:e})),beforeView:async()=>{if(e)return null;let r=t.split("/").pop();return r?await N(()=>Qe(n,t,{path:r})):null}})}async function br(n,t,e){return await Ze(n,t,{direct:r=>N(()=>Rt(n,r,e)),byViewName:r=>N(()=>Et(n,r,t,e)),byViewUrl:r=>N(()=>Ft(n,r,t,e))})}async function yr(n,t,e){return await Ze(n,t,{direct:r=>N(()=>Nt(n,r,e)),byViewName:r=>N(()=>At(n,r,t,e)),byViewUrl:r=>N(()=>Bt(n,r,t,e))})}function pn(n){let t=n.command("workspace").alias("ws").description("Workspace operations");t.option("-j, --job <job>","Specify job").option("-p, --path <path>","Workspace sub path").action(async(e,r)=>{let{config:o,jenkins:s}=await h(),i=Ye(e.job,r,"workspace"),a=await k(o,i),c=String(e.path??"").trim(),l=un(`Loading workspace for job "${a}"...`).start(),u=await hr(s,a,c);if(!u){l.warn(`Workspace not found for job: ${a}. The job may be inside a folder, not run yet, or workspace is disabled.`);return}if(l.succeed(`Workspace loaded for job: ${a}`),!u.length){console.table([{name:"-",type:"-",size:"-",modified:"-",path:"-",url:"-"}]);return}let p=u.map(d=>({name:String(d.name??""),typeRaw:d.type,size:_t(d.size),modified:mr(d.modified),path:pr(c,String(d.path??d.name??""))})),m=j(p.map(d=>d.name)),f=j(p.map(d=>d.path));console.table(p.map(d=>{let b=T(String(d.name??""),m),v=String(d.typeRaw??"");return {name:v==="dir"?w(y.bold.cyan(b)):v==="file"?w(y.green(b)):w(y.gray(b)),size:d.size,modified:d.modified,path:S(String(d.path??""),f)}}));}),t.command("cat").description("Show file content in workspace").argument("<path>","Workspace file path").option("-j, --job <job>","Specify job").option("-o, --out <file>","Save file to path").option("--open","Open file with default application").action(async(e,r,o)=>{let{config:s,jenkins:i}=await h(),a=Ye(r.job,o,"cat"),c=await k(s,a),l=String(e??"").trim();if(!l)throw new g("Path is required.",{hint:'Provide a file path after "cat".',example:"jenkins-cli ws cat dist/index.html"});let u=String(r.out??"").trim(),p=r.open===!0;if(u||p){let f=await yr(i,c,l);if(f===null){console.log(y.yellow(`Workspace file not found: ${l} (job: ${c}).`));return}let d=u||W.join(lr.tmpdir(),W.basename(l)||"file");try{u&&await _.pathExists(u)&&(await _.stat(u)).isDirectory()&&(d=W.join(u,W.basename(l)||"file"));}catch{}await _.ensureDir(W.dirname(d)),await _.writeFile(d,f.data),p?(fr(d),console.log(y.green(`Opened: ${d}`))):console.log(y.green(`Saved to: ${d}`));return}let m=await br(i,c,l);if(m===null){console.log(y.yellow(`Workspace file not found: ${l} (job: ${c}).`));return}process.stdout.write(String(m));}),t.command("wipe").description("Wipe out current workspace").option("-j, --job <job>","Specify job").action(async(e,r)=>{let{config:o,jenkins:s}=await h(),i=Ye(e.job,r,"wipe"),a=await k(o,i);try{if(!(await ce.prompt([{type:"confirm",name:"confirm",message:`Wipe workspace for job "${a}"? This cannot be undone.`,default:!1}]))?.confirm){console.log(y.yellow("Cancelled."));return}}catch(l){if(Je(l)){console.log(y.yellow("Cancelled."));return}throw l}let c=un(`Wiping workspace for job "${a}"...`).start();try{await Wt(s,a),c.succeed(`Workspace wiped for job: ${a}`);}catch(l){throw c.fail(`Failed to wipe workspace for job: ${a}`),l}});}function fn(n){return n.active===!0||n.enabled===!0}function dn(n,t){return String(n.shortName??"").localeCompare(String(t.shortName??""),"en",{sensitivity:"base"})}function gn(n){let t=n.command("plugin").description("Plugin operations");t.command("show").description("Show used plugins").action(async()=>{let{jenkins:e}=await h(),o=(await ie(e)??[]).filter(a=>fn(a)&&String(a.shortName??"").trim());if(o.sort(dn),o.length===0){console.log("No plugins found.");return}let s=j(o.map(a=>a.shortName)),i=j(o.map(a=>a.version));console.table(o.map(a=>({name:S(a.shortName??"",s),version:S(a.version??"",i),enabled:a.enabled===void 0?w("-"):a.enabled,active:a.active===void 0?w("-"):a.active,update:a.hasUpdate===void 0?w("-"):a.hasUpdate})));}),t.command("backup").description("Backup plugins list").requiredOption("-d, --destination <path>","Destination folder").action(async e=>{let{jenkins:r}=await h(),o=String(e.destination??"").trim();if(!o)throw new g("Destination is required.",{hint:"Provide a destination folder with -d or --destination.",example:"jenkins-cli plugin backup -d ./jenkins-backup"});let i=(await ie(r)??[]).filter(l=>fn(l)&&String(l.shortName??"").trim());if(i.sort(dn),i.length===0)throw new g("No plugins found to back up.",{hint:"Check Jenkins permissions or ensure plugins are installed.",example:"jenkins-cli plugin show"});await promises.mkdir(o,{recursive:!0});let a=W.join(o,"plugins.json"),c=W.join(o,"plugins.txt");await promises.writeFile(a,JSON.stringify(i,null,2)),await promises.writeFile(c,`${i.map(l=>{let u=String(l.shortName??"").trim(),p=String(l.version??"").trim();return p?`${u}:${p}`:u}).filter(Boolean).join(`
|
|
43
43
|
`)}
|
|
44
|
-
`),console.log(`Backup completed. ${i.length} plugin(s) saved to ${
|
|
44
|
+
`),console.log(`Backup completed. ${i.length} plugin(s) saved to ${W.resolve(o)}`);});}function kr(n){return n.active===!0||n.enabled===!0}function xr(n){let t=String(n??"").trim();return t?!(/<credentials>/i.test(t)||/com\.cloudbees\.plugins\.credentials\.impl/i.test(t)||/org\.jenkinsci\.plugins\./i.test(t)):!0}function wn(n){n.command("backup").description("Backup Jenkins global config, jobs, plugins, and credentials").requiredOption("-d, --destination <path>","Destination folder").action(async t=>{let{jenkins:e}=await h(),r=String(t.destination??"").trim();if(!r)throw new g("Destination is required.",{hint:"Provide a destination folder with -d or --destination.",example:"jenkins-cli backup -d ./jenkins-backup"});await promises.mkdir(r,{recursive:!0});let o=W.resolve(r),s=[],i=await bt(e);await promises.writeFile(W.join(o,"config.xml"),i);let a=await xt(e,{depth:8}),c=0;for(let m of a){let f=await se(e,m),d=W.join(o,"jobs",...m.split("/"),"config.xml");await promises.mkdir(W.dirname(d),{recursive:!0}),await promises.writeFile(d,f),c+=1;}let u=(await ie(e)??[]).filter(m=>kr(m)&&String(m.shortName??"").trim()).sort((m,f)=>String(m.shortName??"").localeCompare(String(f.shortName??""),"en",{sensitivity:"base"})),p=W.join(o,"plugins");await promises.mkdir(p,{recursive:!0}),await promises.writeFile(W.join(p,"plugins.json"),JSON.stringify(u,null,2)),await promises.writeFile(W.join(p,"plugins.txt"),`${u.map(m=>{let f=String(m.shortName??"").trim(),d=String(m.version??"").trim();return d?`${f}:${d}`:f}).filter(Boolean).join(`
|
|
45
|
+
`)}
|
|
46
|
+
`);try{let m=await yt(e);await promises.writeFile(W.join(o,"credentials.xml"),m);try{let f=await kt(e);await promises.writeFile(W.join(o,"credentials.json"),JSON.stringify(f,null,2));}catch{}xr(m)&&s.push("credentials.xml looks like domain-only data. This often means no readable credentials in system store or missing credentials view permission.");}catch(m){let f=m?.response?.status;s.push(f?`credentials.xml backup skipped (HTTP ${f}, possibly missing permission or plugin).`:"credentials.xml backup skipped due to request failure.");}if(console.log(`Backup completed: ${o}`),console.log("- config.xml: saved"),console.log(`- jobs/: ${c} job config file(s)`),console.log(`- plugins/: ${u.length} plugin(s)`),console.log(`- credentials.xml: ${s.some(m=>m.startsWith("credentials.xml backup skipped"))?"skipped":"saved"}`),s.length){console.log(`
|
|
47
|
+
Warnings:`);for(let m of s)console.log(`- ${m}`);}});}function hn(n){wn(n),Xt(n),Zt(n),sn(n),an(n),tn(n),rn(n),gn(n),zt(n),nn(n),cn(n),on(n),ln(n),pn(n);}function bn(n,t,e){let r=s=>s.options.some(i=>i.long===t||i.short===t),o=s=>{r(s)||s.option(t,e);for(let i of s.commands)o(i);};for(let s of n.commands)o(s);}program.name("jenkins-cli").description(st).version(it,"-v, --version").helpOption("-h, --help").option("--debug","Print Jenkins request params").allowExcessArguments(!1).configureHelp({sortSubcommands:!0,sortOptions:!0}).action(Mt);hn(program);bn(program,"--debug","Print Jenkins request params");async function jr(){try{await program.parseAsync(process.argv);}catch(n){M(n);}}jr();
|