@ts-org/jenkins-cli 3.0.3 → 3.0.4

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 CHANGED
@@ -51,6 +51,7 @@ modes:
51
51
  - sit
52
52
  - uat
53
53
  ```
54
+
54
55
  建议在 `jenkins-cli.yaml` 顶部添加 `# yaml-language-server: $schema=https://cdn.jsdelivr.net/npm/@ts-org/jenkins-cli@latest/schemas/jenkins.json`,以有更好的开发体验,如示例。
55
56
 
56
57
  #### 扩展交互参数
@@ -109,19 +110,19 @@ export function validateTicket(input: string) {
109
110
 
110
111
  ### 🤖 命令参考
111
112
 
112
- #### `trigger` (非交互式触发)
113
+ #### `build` (非交互式触发)
113
114
 
114
115
  适用于 CI 或其他脚本化场景。
115
116
 
116
117
  ```bash
117
118
  # 触发 dev 环境构建
118
- jenkins-cli trigger -b origin/develop -m dev
119
+ jenkins-cli build -b origin/develop -m dev
119
120
 
120
121
  # 同时触发多个环境
121
- jenkins-cli trigger -b origin/develop -m dev,sit
122
+ jenkins-cli build -b origin/develop -m dev,sit
122
123
 
123
124
  # 传入额外参数
124
- jenkins-cli trigger -b origin/develop -m dev --param version=1.2.3 --param force=true
125
+ jenkins-cli build -b origin/develop -m dev --param version=1.2.3 --param force=true
125
126
  ```
126
127
 
127
128
  ---
@@ -130,13 +131,27 @@ jenkins-cli trigger -b origin/develop -m dev --param version=1.2.3 --param force
130
131
 
131
132
  ```bash
132
133
  # 查看最近 20 次构建
133
- jenkins-cli builds list
134
+ jenkins-cli builds
134
135
 
135
136
  # 查看运行中的构建
136
- jenkins-cli builds running
137
+ jenkins-cli builds active
137
138
 
138
139
  # 查看 Jenkins 上所有运行中的构建
139
- jenkins-cli builds running -a
140
+ jenkins-cli builds active -a
141
+
142
+ ```
143
+
144
+ #### `changes` - 变更记录
145
+
146
+ ```bash
147
+ # 查看最近 20 次构建的变更记录
148
+ jenkins-cli changes
149
+
150
+ # 查看最近 50 次构建的变更记录
151
+ jenkins-cli changes -n 50
152
+
153
+ # 查看指定构建的变更记录
154
+ jenkins-cli changes 1234
140
155
  ```
141
156
 
142
157
  #### `job` - Job 管理
@@ -149,23 +164,23 @@ jenkins-cli job list --search 'project-*'
149
164
  jenkins-cli job info
150
165
  ```
151
166
 
152
- #### `log` - 查看日志
167
+ #### `console` - 查看日志
153
168
 
154
169
  ```bash
155
170
  # 查看指定构建号的日志
156
- jenkins-cli log 1234
171
+ jenkins-cli console 1234
157
172
 
158
173
  # 查看最后一次构建日志
159
- jenkins-cli log last
174
+ jenkins-cli console last
160
175
 
161
176
  # 查看最后一次构建成功日志
162
- jenkins-cli log last -s success
177
+ jenkins-cli console last -s success
163
178
 
164
179
  # 查看最后一次构建失败日志
165
- jenkins-cli log last -s failed
180
+ jenkins-cli console last -s failed
166
181
 
167
182
  # 仅输出最后 N 行
168
- jenkins-cli log 1234 -t 200
183
+ jenkins-cli console 1234 -t 200
169
184
  ```
170
185
 
171
186
  #### `stop` - 停止构建
@@ -202,17 +217,29 @@ jenkins-cli params
202
217
 
203
218
  ```bash
204
219
  # 读取当前 Job 的 XML 配置
205
- jenkins-cli config read
220
+ jenkins-cli config show
206
221
 
207
222
  # 以 JSON 格式输出
208
- jenkins-cli config read -f json
223
+ jenkins-cli config show -f json
224
+
225
+ # 备份当前 Job 配置
226
+ jenkins-cli config backup -d ./jenkins-backup
227
+
228
+ # 备份指定 Job 配置
229
+ jenkins-cli config backup -d ./jenkins-backup -j remote-factory-admin
230
+
231
+ # 按 glob 过滤备份多个 Job 配置
232
+ jenkins-cli config backup -d ./jenkins-backup --filter 'remote-*'
233
+
234
+ # 备份所有 Job 配置
235
+ jenkins-cli config backup -d ./jenkins-backup -a
209
236
  ```
210
237
 
211
- #### `whoami` - 用户信息
238
+ #### `me` - 用户信息
212
239
 
213
240
  ```bash
214
241
  # 验证 API Token 并查看当前用户
215
- jenkins-cli whoami
242
+ jenkins-cli me
216
243
  ```
217
244
 
218
245
  ### ❓ FAQ
package/dist/cli.d.ts CHANGED
File without changes
package/dist/cli.js CHANGED
@@ -1,36 +1,39 @@
1
1
  #!/usr/bin/env node
2
- import { program } from 'commander';
3
- import Ye from 'inquirer';
4
- import g from 'chalk';
5
- import We from 'ora';
2
+ import { program, CommanderError } from 'commander';
3
+ import pt from 'inquirer';
4
+ import b from 'chalk';
5
+ import it from 'ora';
6
6
  import { exec } from 'child_process';
7
- import ze, { promisify } from 'util';
8
- import C from 'fs-extra';
9
- import Ne from 'js-yaml';
10
- import S from 'path';
11
- import Fe from 'axios';
12
- import _e from 'jiti';
7
+ import ft, { promisify } from 'util';
8
+ import N from 'fs-extra';
9
+ import Ye from 'js-yaml';
10
+ import R from 'path';
11
+ import tt from 'axios';
12
+ import at from 'jiti';
13
13
  import { fileURLToPath } from 'url';
14
+ import { promises } from 'fs';
14
15
  import { XMLParser } from 'fast-xml-parser';
15
16
 
16
- var H="3.0.3",Y="Jenkins deployment CLI";var V=promisify(exec);async function z(){try{let{stdout:e}=await V("git branch --show-current"),t=e.trim();if(!t)throw new Error("Not on any branch (detached HEAD state)");return t}catch{throw new Error("Failed to get current branch. Are you in a git repository?")}}async function X(){try{let{stdout:e}=await V('git branch -r --format="%(refname:short)"');return e.split(`
17
- `).filter(t=>t.includes("/")&&!t.includes("HEAD"))}catch{throw new Error("Failed to list branches. Are you in a git repository?")}}var B="jenkins-cli.yaml",T="package.json",U="jenkins-cli",Ee="jenkinsCli";function ee(e,t=process.cwd()){let n=t;for(;;){let r=S.join(n,e);if(C.existsSync(r))return r;let o=S.dirname(n);if(o===n)return null;n=o;}}function Be(e=process.cwd()){return ee(B,e)}function Le(e=process.cwd()){let t=ee(T,e);return t?S.dirname(t):null}function Ie(e){return !!(e.apiToken&&e.job&&Array.isArray(e.modes)&&e.modes.length>0)}async function Z(e){let t=await C.readFile(e,"utf-8"),n=Ne.load(t);if(!n||typeof n!="object")throw new Error(`Invalid config in ${B}: expected a YAML object`);return n}async function qe(e){let t=S.join(e,T);if(!await C.pathExists(t))return {};let n=await C.readFile(t,"utf-8"),r=JSON.parse(n),o=r[U]??r[Ee];if(o==null)return {};if(typeof o!="object"||Array.isArray(o))throw new Error(`Invalid ${T} config: "${U}" must be an object`);return o}async function te(){let e=process.cwd(),t=Le(e)??e,n=S.join(t,B),r={},o=S.dirname(t),a=Be(o);a&&await C.pathExists(a)&&(r=await Z(a));let i=await qe(t);r={...r,...i};let s=await C.pathExists(n)?await Z(n):{};if(r={...r,...s},!Ie(r))throw new Error(`Config incomplete or not found: tried ${B} in project root, "${U}" in $
18
- {PACKAGE_JSON}, and walking up from cwd. Required: apiToken, job, modes (non-empty array)`);return {...r,projectRoot:t}}var D={maxRedirects:0,validateStatus:e=>e>=200&&e<400};function w(e){return `job/${e.split("/").map(n=>n.trim()).filter(Boolean).map(encodeURIComponent).join("/job/")}`}function W(e){let t=Array.isArray(e)?e.find(o=>o?.parameters):void 0,n=Array.isArray(t?.parameters)?t.parameters:[],r={};for(let o of n)o?.name&&(r[String(o.name)]=o?.value);return r}function Oe(e){try{let n=new URL(e).pathname.split("/").filter(Boolean),r=[];for(let o=0;o<n.length-1;o++)n[o]==="job"&&n[o+1]&&r.push(decodeURIComponent(n[o+1]));return r.join("/")}catch{return ""}}async function Te(e,t){let r=(await e.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:W(r.actions)}}function Ue(e,t=400){try{let r=(typeof e=="string"?e:JSON.stringify(e??"",null,2)).trim();return r?r.length>t?`${r.slice(0,t)}...`:r:""}catch{return ""}}function re(e){let t=e.match(/^(https?):\/\/([^:]+):([^@]+)@(.+)$/);if(!t)throw new Error("Invalid apiToken format. Expected: http(s)://username:token@host:port");let[,n,r,o,a]=t,i=`${n}://${a.replace(/\/$/,"")}/`,s=Fe.create({baseURL:i,auth:{username:r,password:o},proxy:!1,timeout:3e4});return {baseURL:i,auth:{username:r,password:o},axios:s,crumbForm:void 0}}async function oe(e,t=5e3){try{let n=await e.axios.get("crumbIssuer/api/json",{timeout:t}),{data:r}=n;r?.crumbRequestField&&r?.crumb&&(e.axios.defaults.headers.common[r.crumbRequestField]=r.crumb,e.crumbForm={field:r.crumbRequestField,value:r.crumb});let o=n.headers["set-cookie"];if(o){let a=Array.isArray(o)?o.map(i=>i.split(";")[0].trim()):[String(o).split(";")[0].trim()];e.axios.defaults.headers.common.Cookie=a.join("; ");}}catch{}}function M(e){return e.crumbPromise||(e.crumbPromise=oe(e,5e3)),e.crumbPromise}async function _(e){await M(e),e.crumbForm||(e.crumbPromise=oe(e,15e3),await e.crumbPromise);}async function $(e,t){let r=(await e.axios.get("queue/api/json?tree=items[id,task[name],actions[parameters[name,value]],why]")).data.items;if(t){let o=t.trim(),a=o.split("/").filter(Boolean).pop();return r.filter(i=>{let s=i.task?.name;return s===o||(a?s===a:!1)})}return r}async function v(e,t){let n=await e.axios.get(`${w(t)}/api/json?tree=builds[number,url,building,result,timestamp,duration,estimatedDuration,actions[parameters[name,value]]]`);return (Array.isArray(n.data?.builds)?n.data.builds:[]).filter(o=>o?.building).map(o=>({...o,parameters:W(o.actions)}))}async function L(e){let t=await e.axios.get("computer/api/json?tree=computer[displayName,executors[currentExecutable[number,url]],oneOffExecutors[currentExecutable[number,url]]]"),n=Array.isArray(t.data?.computer)?t.data.computer:[],r=[];for(let i of n){let s=Array.isArray(i?.executors)?i.executors:[],u=Array.isArray(i?.oneOffExecutors)?i.oneOffExecutors:[];for(let l of [...s,...u]){let c=l?.currentExecutable;c?.url&&r.push({number:Number(c.number),url:String(c.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 s=await Te(e,i.url),u=Oe(String(s?.url??i.url));return {...s,job:u}}))).filter(i=>i?.building)}async function P(e,t){return await _(e),await e.axios.post("queue/cancelItem",new URLSearchParams({id:t.toString()}),D),!0}async function A(e,t,n){try{await _(e),await e.axios.post(`${w(t)}/${n}/stop/`,new URLSearchParams({}),D);}catch(r){let o=r.response?.status;if(o===403){let a=typeof r.response?.data=="string"?r.response.data.slice(0,200):JSON.stringify(r.response?.data??"").slice(0,200),i=/crumb|csrf/i.test(a);console.log(g.red("[Error] 403 Forbidden: Jenkins refused the stop request (likely permissions or CSRF).")),console.log(g.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).":a?`[Hint] Jenkins response: ${a}`:'[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 #${n} could not be stopped (HTTP ${o}). Assuming it finished.`);return}throw r}}async function I(e,t,n){let r="branch",o="mode",a=n[o];a&&console.log(`Checking for conflicting builds for mode: ${a}...`);let[i,s]=await Promise.all([$(e,t),v(e,t)]),u=(m,f)=>{let b=m.actions?.find(R=>R.parameters);return b?b.parameters.find(R=>R.name===f)?.value:void 0},l=n[r];if(a&&l){let m=i.find(f=>u(f,o)===a&&u(f,r)===l);if(m)return new URL(`queue/item/${m.id}/`,e.baseURL).toString()}let c=!1;if(a)for(let m of s)u(m,o)===a&&(console.log(`Stopping running build #${m.number} (mode=${a})...`),await A(e,t,m.number),c=!0);c&&await new Promise(m=>setTimeout(m,1e3));try{return await _(e),(await e.axios.post(`${w(t)}/buildWithParameters/`,new URLSearchParams({...n}),D)).headers.location||""}catch(m){let f=m?.response?.status,b=Ue(m?.response?.data);if(f===400){let y=[];y.push("Hint: Jenkins returned 400. Common causes: job is not parameterized, parameter names do not match, or the job endpoint differs (e.g. multibranch jobs)."),y.push(`Hint: This CLI sends parameters "${r}" and "${o}". Ensure your Jenkins Job has matching parameter names.`);let R=b?`
19
- Jenkins response (snippet):
20
- ${b}`:"";throw new Error(`Request failed with status code 400.${R}
21
- ${y.join(`
22
- `)}`)}if(f){let y=b?`
23
- Jenkins response (snippet):
24
- ${b}`:"";throw new Error(`Request failed with status code ${f}.${y}`)}throw m}}async function ie(e){return (await e.axios.get("whoAmI/api/json")).data}async function se(e){return (await e.axios.get("api/json?tree=jobs[name,url,color]")).data.jobs??[]}async function q(e,t){return (await e.axios.get(`${w(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}async function ae(e,t,n){let r=Math.max(1,n?.limit??20);return ((await e.axios.get(`${w(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:W(i.actions)}))}async function ce(e,t,n){let r=await e.axios.get(`${w(t)}/${n}/consoleText`,{responseType:"text"});return String(r.data??"")}async function ue(e,t){return ((await e.axios.get(`${w(t)}/api/json?tree=property[parameterDefinitions[name,type,description,defaultParameterValue[value],choices]]`)).data?.property??[]).flatMap(a=>a?.parameterDefinitions??[]).filter(Boolean).map(a=>({name:a.name,type:a.type,description:a.description,default:a.defaultParameterValue?.value,choices:a.choices}))}async function le(e,t){let n=await e.axios.get(`${w(t)}/config.xml`,{responseType:"text"});return String(n.data??"")}async function p(){let e=We("Loading configuration...").start();try{let t=await te();e.succeed("Configuration loaded");let n=re(t.apiToken);return M(n),{config:t,jenkins:n}}catch(t){e.fail(g.red(t.message)),process.exit(1);}}var Ge=_e(fileURLToPath(import.meta.url),{interopDefault:!0});async function fe(e){return await Promise.resolve(e)}function Ke(e){let t=String(e??"").trim();if(!t)return null;let n=t.split(":");if(n.length<2)return null;if(n.length===2){let[a,i]=n;return !a||!i?null:{file:a,exportName:i}}let r=n.at(-1);if(!r)return null;let o=n.slice(0,-2).join(":");return o?{file:o,exportName:r}:null}function He(e,t){return S.isAbsolute(t)?t:S.join(e,t)}function pe(e){return !!e&&typeof e=="object"&&!Array.isArray(e)}async function N(e,t){let n=Ke(t);if(!n)return null;let r=He(e,n.file);if(!await C.pathExists(r))throw new Error(`configs reference not found: ${n.file}`);let o=Ge(r),a=pe(o)?o:{default:o},i=n.exportName==="default"?a.default:a[n.exportName];if(i===void 0)throw new Error(`configs reference export not found: ${t}`);return {value:i}}async function de(e,t){if(typeof t!="string")return t;let n=await N(e,t);if(!n)return t;if(typeof n.value=="function"){let r=n.value();return await fe(r)}return await fe(n.value)}async function ge(e,t){let n=Array.isArray(e)?e:[];if(n.length===0)return [];let r=String(t.projectRoot??"").trim()||process.cwd(),o=[];for(let a of n){if(!pe(a))continue;let i={...a};if(i.choices!==void 0){i.choices=await de(r,i.choices);let s=String(i.type??"").toLowerCase(),u=i.choices;if((s==="list"||s==="rawlist"||s==="checkbox")&&typeof u!="function"&&!Array.isArray(u))if(u==null)i.choices=[];else if(typeof u=="string"||typeof u=="number"||typeof u=="boolean")i.choices=[String(u)];else if(typeof u[Symbol.iterator]=="function")i.choices=Array.from(u).map(c=>String(c));else throw new Error(`configs "${String(i.name??"")}" choices must resolve to an array (got ${typeof u})`)}if(i.default!==void 0&&(i.default=await de(r,i.default)),i.when!==void 0){let s=i.when;if(typeof s=="string"){let u=await N(r,s);if(!u)i.when=s;else {if(typeof u.value!="function"&&typeof u.value!="boolean")throw new Error(`when reference must be a function or boolean: ${s}`);i.when=u.value;}}else (typeof s=="function"||typeof s=="boolean")&&(i.when=s);}if(i.validate!==void 0){let s=i.validate;if(typeof s=="string"){let u=await N(r,s);if(!u)i.validate=s;else {if(typeof u.value!="function")throw new Error(`validate reference must be a function: ${s}`);i.validate=u.value;}}else typeof s=="function"&&(i.validate=s);}if(i.filter!==void 0){let s=i.filter;if(typeof s=="string"){let u=await N(r,s);if(!u)i.filter=s;else {if(typeof u.value!="function")throw new Error(`filter reference must be a function: ${s}`);i.filter=u.value;}}else typeof s=="function"&&(i.filter=s);}if(i.transformer!==void 0){let s=i.transformer;if(typeof s=="string"){let u=await N(r,s);if(!u)i.transformer=s;else {if(typeof u.value!="function")throw new Error(`transformer reference must be a function: ${s}`);i.transformer=u.value;}}else typeof s=="function"&&(i.transformer=s);}o.push(i);}return o}function be(e,t){let n=new Set(t),r={};for(let[o,a]of Object.entries(e))if(!n.has(o)&&a!==void 0){if(a===null){r[o]="";continue}if(Array.isArray(a)){r[o]=a.map(i=>String(i)).join(",");continue}if(typeof a=="object"){try{r[o]=JSON.stringify(a);}catch{r[o]=String(a);}continue}r[o]=String(a);}return r}async function ye(){console.log(g.bold.blue(`
17
+ var se="3.0.4",ae="Jenkins deployment CLI";var p=class extends Error{hint;example;details;exitCode;constructor(e,t={}){super(e),this.name="UserError",this.hint=t.hint,this.example=t.example,this.details=t.details,this.exitCode=t.exitCode??1;}};function Ke(n){return n instanceof p?n:n instanceof CommanderError?new p(n.message,{hint:"Check the command usage and options.",example:"jenkins-cli --help",exitCode:n.exitCode??1}):n instanceof Error?new p(n.message,{hint:"Check your input and try again.",example:"jenkins-cli --help"}):new p("Unknown error",{example:"jenkins-cli --help"})}function J(n){let e=Ke(n);if(console.error(b.red(`
18
+ \u274C ${e.message}
19
+ `)),e.details&&console.error(b.gray(e.details)),e.hint&&console.error(b.yellow(`Hint: ${e.hint}`)),e.example!==""){let t=e.example??"jenkins-cli --help";console.error(b.cyan(`Example: ${t}`));}console.error(b.gray('Run "jenkins-cli --help" for usage.')),process.exitCode=e.exitCode;}var ce=promisify(exec);async function le(){try{let{stdout:n}=await ce("git branch --show-current"),e=n.trim();if(!e)throw new p("Not on any branch (detached HEAD state).",{hint:"Checkout a branch before running this command.",example:"git checkout main"});return e}catch{throw new p("Failed to get current branch.",{hint:"Make sure you are inside a git repository.",example:"cd /path/to/repo && jenkins-cli"})}}async function ue(){try{let{stdout:n}=await ce('git branch -r --format="%(refname:short)"');return n.split(`
20
+ `).filter(e=>e.includes("/")&&!e.includes("HEAD"))}catch{throw new p("Failed to list branches.",{hint:"Make sure you are inside a git repository.",example:"cd /path/to/repo && jenkins-cli"})}}var P="jenkins-cli.yaml",T="package.json",F="jenkins-cli",Ve="jenkinsCli";function pe(n,e=process.cwd()){let t=e;for(;;){let r=R.join(t,n);if(N.existsSync(r))return r;let o=R.dirname(t);if(o===t)return null;t=o;}}function ze(n=process.cwd()){return pe(P,n)}function Xe(n=process.cwd()){let e=pe(T,n);return e?R.dirname(e):null}function Ze(n){return !!(n.apiToken&&n.job&&Array.isArray(n.modes)&&n.modes.length>0)}async function me(n){let e=await N.readFile(n,"utf-8"),t=Ye.load(e);if(!t||typeof t!="object")throw new p(`Invalid config in ${P}. Expected a YAML object.`,{hint:"Top-level config must be key/value pairs.",example:`${P}:
21
+ apiToken: http://user:token@host
22
+ job: my-job
23
+ modes: [dev]`});return t}async function et(n){let e=R.join(n,T);if(!await N.pathExists(e))return {};let t=await N.readFile(e,"utf-8"),r=JSON.parse(t),o=r[F]??r[Ve];if(o==null)return {};if(typeof o!="object"||Array.isArray(o))throw new p(`Invalid ${T} config: "${F}" must be an object.`,{hint:"Use an object for the config section.",example:`"${F}": { "apiToken": "http://user:token@host", "job": "my-job", "modes": ["dev"] }`});return o}async function de(){let n=process.cwd(),e=Xe(n)??n,t=R.join(e,P),r={},o=R.dirname(e),s=ze(o);s&&await N.pathExists(s)&&(r=await me(s));let i=await et(e);r={...r,...i};let a=await N.pathExists(t)?await me(t):{};if(r={...r,...a},!Ze(r))throw new p("Config incomplete or not found.",{hint:`Tried ${P} in project root, "${F}" in ${T}, and walking up from cwd. Required: apiToken, job, modes (non-empty array).`,example:`${P}:
24
+ apiToken: http://user:token@host
25
+ job: my-job
26
+ modes:
27
+ - dev`});return {...r,projectRoot:e}}var Y={maxRedirects:0,validateStatus:n=>n>=200&&n<400};function j(n){return `job/${n.split("/").map(t=>t.trim()).filter(Boolean).map(encodeURIComponent).join("/job/")}`}function D(n){let e=Array.isArray(n)?n.find(o=>o?.parameters):void 0,t=Array.isArray(e?.parameters)?e.parameters:[],r={};for(let o of t)o?.name&&(r[String(o.name)]=o?.value);return r}function nt(n){try{let t=new URL(n).pathname.split("/").filter(Boolean),r=[];for(let o=0;o<t.length-1;o++)t[o]==="job"&&t[o+1]&&r.push(decodeURIComponent(t[o+1]));return r.join("/")}catch{return ""}}async function rt(n,e){let r=(await n.axios.get(new URL("api/json?tree=number,url,building,result,timestamp,duration,estimatedDuration,fullDisplayName,displayName,actions[parameters[name,value]]",e).toString())).data??{};return {...r,parameters:D(r.actions)}}function ot(n,e=400){try{let r=(typeof n=="string"?n:JSON.stringify(n??"",null,2)).trim();return r?r.length>e?`${r.slice(0,e)}...`:r:""}catch{return ""}}function ge(n){let e=n.match(/^(https?):\/\/([^:]+):([^@]+)@(.+)$/);if(!e)throw new p("Invalid apiToken format.",{hint:"Expected: http(s)://username:token@host:port",example:"http://user:token@jenkins.example.com:8080"});let[,t,r,o,s]=e,i=`${t}://${s.replace(/\/$/,"")}/`,a=tt.create({baseURL:i,auth:{username:r,password:o},proxy:!1,timeout:3e4});return {baseURL:i,auth:{username:r,password:o},axios:a,crumbForm:void 0}}async function be(n,e=5e3){try{let t=await n.axios.get("crumbIssuer/api/json",{timeout:e}),{data:r}=t;r?.crumbRequestField&&r?.crumb&&(n.axios.defaults.headers.common[r.crumbRequestField]=r.crumb,n.crumbForm={field:r.crumbRequestField,value:r.crumb});let o=t.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 V(n){return n.crumbPromise||(n.crumbPromise=be(n,5e3)),n.crumbPromise}async function z(n){await V(n),n.crumbForm||(n.crumbPromise=be(n,15e3),await n.crumbPromise);}async function A(n,e){let r=(await n.axios.get("queue/api/json?tree=items[id,task[name],actions[parameters[name,value]],why]")).data.items;if(e){let o=e.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 L(n,e){let t=await n.axios.get(`${j(e)}/api/json?tree=builds[number,url,building,result,timestamp,duration,estimatedDuration,actions[parameters[name,value]]]`);return (Array.isArray(t.data?.builds)?t.data.builds:[]).filter(o=>o?.building).map(o=>({...o,parameters:D(o.actions)}))}async function W(n){let e=await n.axios.get("computer/api/json?tree=computer[displayName,executors[currentExecutable[number,url]],oneOffExecutors[currentExecutable[number,url]]]"),t=Array.isArray(e.data?.computer)?e.data.computer:[],r=[];for(let i of t){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 rt(n,i.url),c=nt(String(a?.url??i.url));return {...a,job:c}}))).filter(i=>i?.building)}async function I(n,e){return await z(n),await n.axios.post("queue/cancelItem",new URLSearchParams({id:e.toString()}),Y),!0}async function U(n,e,t){try{await z(n),await n.axios.post(`${j(e)}/${t}/stop/`,new URLSearchParams({}),Y);}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(b.red("[Error] 403 Forbidden: Jenkins refused the stop request (likely permissions or CSRF).")),console.log(b.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 #${t} could not be stopped (HTTP ${o}). Assuming it finished.`);return}throw r}}async function M(n,e,t){let r="branch",o="mode",s=t[o];s&&console.log(`Checking for conflicting builds for mode: ${s}...`);let[i,a]=await Promise.all([A(n,e),L(n,e)]),c=(m,d)=>{let h=m.actions?.find(B=>B.parameters);return h?h.parameters.find(B=>B.name===d)?.value:void 0},l=t[r];if(s&&l){let m=i.find(d=>c(d,o)===s&&c(d,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 U(n,e,m.number),u=!0);u&&await new Promise(m=>setTimeout(m,1e3));try{return await z(n),(await n.axios.post(`${j(e)}/buildWithParameters/`,new URLSearchParams({...t}),Y)).headers.location||""}catch(m){let d=m?.response?.status,h=ot(m?.response?.data);if(d===400){let w=h?`Jenkins response (snippet):
28
+ ${h}`:void 0;throw new p("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:w})}if(d){let w=h?`Jenkins response (snippet):
29
+ ${h}`:void 0;throw new p(`Request failed with status code ${d}.`,{hint:"Check Jenkins job permissions and parameters.",example:"jenkins-cli me",details:w})}throw m}}async function he(n){return (await n.axios.get("whoAmI/api/json")).data}async function q(n){return (await n.axios.get("api/json?tree=jobs[name,url,color]")).data.jobs??[]}async function Q(n,e){try{let r=(await n.axios.get(`${j(e)}/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(e??"").trim();if(!o&&!s)throw new p(`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 p(`Job not found: ${i}`,{hint:`Jenkins returned job "${o||s}".`,example:"jenkins-cli console last -j my-job -s success"});return r}catch(t){if(t?.response?.status===404){let o=String(e??"").trim();throw new p(`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 t}}async function ye(n,e,t){let r=Math.max(1,t?.limit??20);return ((await n.axios.get(`${j(e)}/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:D(i.actions)}))}async function we(n,e,t){let r=Math.max(1,t?.limit??20);return ((await n.axios.get(`${j(e)}/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 je(n,e,t){let o=(await n.axios.get(`${j(e)}/${t}/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:D(o.actions)}}async function xe(n,e,t){let r=await n.axios.get(`${j(e)}/${t}/consoleText`,{responseType:"text"});return String(r.data??"")}async function ke(n,e){return ((await n.axios.get(`${j(e)}/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 X(n,e){let t=await n.axios.get(`${j(e)}/config.xml`,{responseType:"text"});return String(t.data??"")}async function g(){let n=it("Loading configuration...").start();try{let e=await de();n.succeed("Configuration loaded");let t=ge(e.apiToken);return V(t),{config:e,jenkins:t}}catch(e){J(e),process.exit(1);}}var lt=at(fileURLToPath(import.meta.url),{interopDefault:!0});async function Se(n){return await Promise.resolve(n)}function ut(n){let e=String(n??"").trim();if(!e)return null;let t=e.split(":");if(t.length<2)return null;if(t.length===2){let[s,i]=t;return !s||!i?null:{file:s,exportName:i}}let r=t.at(-1);if(!r)return null;let o=t.slice(0,-2).join(":");return o?{file:o,exportName:r}:null}function mt(n,e){return R.isAbsolute(e)?e:R.join(n,e)}function ve(n){return !!n&&typeof n=="object"&&!Array.isArray(n)}async function Je(n,e){let t=ut(e);if(!t)return null;let r=mt(n,t.file);if(!await N.pathExists(r))throw new p(`configs reference not found: ${t.file}`,{hint:"Check the file path (relative to project root) and file name.",example:'configs: [{ choices: "./scripts/prompts.ts:choices" }]'});let o=lt(r),s=ve(o)?o:{default:o},i=t.exportName==="default"?s.default:s[t.exportName];if(i===void 0)throw new p(`configs reference export not found: ${e}`,{hint:"Make sure the export exists in the referenced file.",example:'export const choices = ["dev", "uat"]'});return {value:i}}async function _(n,e,t){if(typeof e!="string")return e;let r=await Je(n,e);if(!r)return e;if(!t.allow(r.value))throw new p(t.error(e),{hint:t.hint,example:t.example});return r.value}async function $e(n,e){if(typeof e!="string")return e;let t=await Je(n,e);if(!t)return e;if(typeof t.value=="function"){let r=t.value();return await Se(r)}return await Se(t.value)}async function Pe(n,e){let t=Array.isArray(n)?n:[];if(t.length===0)return [];let r=String(e.projectRoot??"").trim()||process.cwd(),o=[];for(let s of t){if(!ve(s))continue;let i={...s};if(i.choices!==void 0){i.choices=await $e(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 p(`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 $e(r,i.default)),i.when!==void 0&&(i.when=await _(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 _(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 _(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 _(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 Ne(n,e){let t=new Set(e),r={};for(let[o,s]of Object.entries(n))if(!t.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 Re(){console.log(b.bold.blue(`
25
30
  \u{1F680} Jenkins CLI - Jenkins Deployment CLI
26
- `));let{config:e,jenkins:t}=await p(),[n,r]=await Promise.all([X(),z()]),o=()=>{console.log(g.yellow(`
27
- \u{1F44B} Cancelled by user`)),process.exit(130);},a,i={};try{process.prependOnceListener("SIGINT",o);let c=await ge(e.configs,{projectRoot:e.projectRoot}),m=new Set(["branch","modes","mode"]);for(let b of c){let y=String(b?.name??"").trim();if(m.has(y))throw new Error(`configs name "${y}" is reserved. Use another name.`)}let f=await Ye.prompt([{type:"list",name:"branch",message:"\u8BF7\u9009\u62E9\u8981\u6253\u5305\u7684\u5206\u652F:",choices:n,default:n.indexOf(r)},{type:"checkbox",name:"modes",message:"\u8BF7\u9009\u62E9\u8981\u6253\u5305\u7684\u73AF\u5883:",choices:e.modes,validate:b=>b.length===0?"You must select at least one environment":!0},...c]);a={branch:String(f.branch??""),modes:f.modes??[]},i=be(f,["branch","modes"]);}catch(c){let m=c,f=m?.message?String(m.message):String(m);((m?.name?String(m.name):"")==="ExitPromptError"||f.toLowerCase().includes("cancelled")||f.toLowerCase().includes("canceled"))&&(console.log(g.yellow(`
28
- \u{1F44B} Cancelled by user`)),process.exit(0)),console.log(g.red(`
29
- \u274C Prompt failed: ${f}
30
- `)),process.exit(1);}finally{process.off("SIGINT",o);}console.log();let s=!1,u=()=>{s||(s=!0,console.log());},l=a.modes.map(async c=>{let m=We(`Triggering build for ${g.yellow(c)}...`).start();try{let f=await I(t,e.job,{...i,branch:a.branch,mode:c});u(),m.succeed(`${g.green(c)} - Triggered! Queue: ${f}`);}catch(f){throw u(),m.fail(`${g.red(c)} - ${f.message}`),f}});try{await Promise.all(l);}catch{console.log(g.bold.red(`
31
+ `));let{config:n,jenkins:e}=await g(),[t,r]=await Promise.all([ue(),le()]),o=()=>{console.log(b.yellow(`
32
+ \u{1F44B} Cancelled by user`)),process.exit(130);},s,i={};try{process.prependOnceListener("SIGINT",o);let u=await Pe(n.configs,{projectRoot:n.projectRoot}),m=new Set(["branch","modes","mode"]);for(let h of u){let w=String(h?.name??"").trim();if(m.has(w))throw new p(`configs name "${w}" is reserved.`,{hint:"Use another name in your extra prompt config.",example:"name: env"})}let d=await pt.prompt([{type:"list",name:"branch",message:"\u8BF7\u9009\u62E9\u8981\u6253\u5305\u7684\u5206\u652F:",choices:t,default:t.indexOf(r)},{type:"checkbox",name:"modes",message:"\u8BF7\u9009\u62E9\u8981\u6253\u5305\u7684\u73AF\u5883:",choices:n.modes,validate:h=>h.length===0?"You must select at least one environment":!0},...u]);s={branch:String(d.branch??""),modes:d.modes??[]},i=Ne(d,["branch","modes"]);}catch(u){let m=u,d=m?.message?String(m.message):String(m),h=m?.name?String(m.name):"";(h==="ExitPromptError"||d.toLowerCase().includes("cancelled")||d.toLowerCase().includes("canceled"))&&(console.log(b.yellow(`
33
+ \u{1F44B} Cancelled by user`)),process.exit(0)),J(new p(`Prompt failed: ${d}`,{hint:h?`Error: ${h}`:""})),process.exit(1);}finally{process.off("SIGINT",o);}console.log();let a=!1,c=()=>{a||(a=!0,console.log());},l=s.modes.map(async u=>{let m=it(`Triggering build for ${b.yellow(u)}...`).start();try{let d=await M(e,n.job,{...i,branch:s.branch,mode:u});c(),m.succeed(`${b.green(u)} - Triggered! Queue: ${d}`);}catch(d){throw c(),m.fail(`${b.red(u)} - ${d.message}`),d}});try{await Promise.all(l);}catch{console.log(b.bold.red(`
31
34
  \u274C Some builds failed. Check the output above.
32
- `)),process.exit(1);}}function h(e,t){return (t??"").trim()||e}function x(e,t){let n=Number(e);if(!Number.isInteger(n)||n<0)throw new Error(`${t} must be a non-negative integer`);return n}function we(e){let t=e.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 n=>{let{config:r,jenkins:o}=await p(),a=n.job?h(r.job,n.job):void 0,i=await $(o,a);console.table((i??[]).map(s=>({id:s.id,job:s.task?.name,why:s.why})));}),t.command("cancel").description("Cancel a queued build item").argument("<id>").action(async n=>{let{jenkins:r}=await p(),o=await P(r,x(n,"id"));console.log(o?g.green("Cancelled"):g.red("Cancel failed"));});}function d(e){return {[ze.inspect.custom]:()=>e}}function k(e){let t=String(e??""),n=t.trim();if(!n)return d(g.gray("-"));let r=a=>d(a),o=n.toLowerCase();if(o.startsWith("http://")||o.startsWith("https://"))try{let i=(new URL(n).hostname??"").toLowerCase(),s=i==="localhost"||i==="127.0.0.1"||i==="::1",u=/^10\./.test(i)||/^192\.168\./.test(i)||/^127\./.test(i)||/^172\.(1[6-9]|2\d|3[0-1])\./.test(i);return r(s||u?g.cyanBright(t):g.hex("#4EA1FF")(t))}catch{return r(g.hex("#4EA1FF")(t))}return o.startsWith("ws://")||o.startsWith("wss://")?r(g.cyan(t)):o.startsWith("ssh://")||o.startsWith("git+ssh://")||o.startsWith("git@")?r(g.magenta(t)):o.startsWith("file://")?r(g.yellow(t)):o.startsWith("mailto:")?r(g.green(t)):o.startsWith("javascript:")||o.startsWith("data:")?r(g.red(t)):n.startsWith("/")||n.startsWith("./")||n.startsWith("../")?r(g.cyan(t)):/^[a-z0-9.-]+(?::\d+)?(\/|$)/i.test(n)?r(g.blue(t)):r(t)}function J(e){let t=new Date(e),n=r=>String(r).padStart(2,"0");return `${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}:${n(t.getSeconds())}`}function E(e,t){if(t===!0)return d(g.cyan("BUILDING"));let n=String(e??"").toUpperCase();return d(n?n==="SUCCESS"?g.green(n):n==="ABORTED"?g.gray(n):n==="FAILURE"?g.red(n):n==="UNSTABLE"?g.yellow(n):n==="NOT_BUILT"?g.gray(n):n:"-")}function Q(e){let t=String(e??"");if(!t)return d("-");let n=t.endsWith("_anime"),r=n?t.slice(0,-6):t,o=(()=>{switch(r){case"blue":return n?g.blueBright(t):g.blue(t);case"red":return n?g.redBright(t):g.red(t);case"yellow":return n?g.yellowBright(t):g.yellow(t);case"aborted":return g.gray(t);case"disabled":case"notbuilt":case"grey":case"gray":return g.gray(t);default:return t}})();return d(o)}function Xe(e){let t=Object.entries(e??{}).filter(([r])=>r);if(!t.length)return d("-");t.sort(([r],[o])=>r.localeCompare(o,"en",{sensitivity:"base"}));let n=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(", ");return d(n)}function je(e){let t=e.command("builds").description("Build operations");t.command("list").alias("ls").description("List builds").option("-j, --job <job>","Specify job").option("-n, --limit <n>","Limit","20").action(async n=>{let{config:r,jenkins:o}=await p(),a=h(r.job,n.job),i=await ae(o,a,{limit:Number(n.limit)});console.table(i.map(s=>({number:s.number,result:E(s.result,s.building),building:s.building,durationS:Number((Number(s.duration??0)/1e3).toFixed(3)),date:d(J(Number(s.timestamp??0)))})));}),t.command("running").description("List running builds").option("-j, --job <job>","Specify job").option("-a, --all","Query all running builds on Jenkins").action(async n=>{let{config:r,jenkins:o}=await p(),a=n.all?await L(o):await v(o,h(r.job,n.job));console.table((a??[]).map(i=>({...n.all?{job:d(String(i.job??""))}:{},number:i.number,date:d(i.timestamp?J(Number(i.timestamp)):"-"),parameters:Xe(i.parameters),url:k(String(i.url??""))})));});}function xe(e){let t=e.command("log").description("Fetch build console log"),n=async(r,o,a)=>{let{jenkins:i}=await p(),s=await ce(i,r,o);if(a.tail){let u=x(a.tail,"tail"),l=s.split(`
33
- `);console.log(l.slice(Math.max(0,l.length-u)).join(`
34
- `));return}process.stdout.write(s);};t.argument("<id>").option("-j, --job <job>","Specify job").option("-t, --tail <n>","Only output the last N lines").action(async(r,o)=>{let{config:a}=await p(),i=h(a.job,o.job),s=x(r,"id");await n(i,s,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("-t, --tail <n>","Only output the last N lines").action(async r=>{let{config:o,jenkins:a}=await p(),i=h(o.job,r.job),s=String(r.status??"any").toLowerCase();if(!["any","success","failed"].includes(s))throw new Error(`Invalid status: ${r.status}. Use success | failed | any.`);let u=await q(a,i),l=s==="success"?u?.lastSuccessfulBuild:s==="failed"?u?.lastFailedBuild:u?.lastBuild,c=Number(l?.number);if(!c){let m=s==="success"?"successful":s==="failed"?"failed":"last";throw new Error(`No ${m} build found for job: ${i}`)}await n(i,c,r);});}function ke(e){e.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,n)=>{let{config:r,jenkins:o}=await p(),a=h(r.job,n.job);if(n.ALL){let[i,s]=await Promise.all([$(o),L(o)]),u=(i??[]).map(c=>Number(c.id)).filter(c=>!Number.isNaN(c)),l=(s??[]).map(c=>({number:Number(c.number),job:String(c.job??"")})).filter(c=>c.job&&!Number.isNaN(c.number));for(let c of u)await P(o,c);for(let c of l)await A(o,c.job,c.number);console.log(g.green(`Requested: cancelled ${u.length} queue item(s), stopped ${l.length} running build(s).`));return}if(n.all){let[i,s]=await Promise.all([$(o,a),v(o,a)]),u=(i??[]).map(c=>Number(c.id)).filter(c=>!Number.isNaN(c)),l=(s??[]).map(c=>Number(c.number)).filter(c=>!Number.isNaN(c));for(let c of u)await P(o,c);for(let c of l)await A(o,a,c);console.log(g.green(`Requested: cancelled ${u.length} queue item(s), stopped ${l.length} running build(s).`));return}if(!t){console.log(g.red("Missing build id. Provide <id> or use -a/--all."));return}await A(o,a,x(t,"id")),console.log(g.green("Stop requested"));});}function Ce(e){e.command("params").description("Show job parameter definitions").option("-j, --job <job>","Specify job").action(async t=>{let{config:n,jenkins:r}=await p(),o=h(n.job,t.job),a=await ue(r,o),i=Math.max(0,...a.map(s=>String(s?.name??"").length));console.table((a??[]).map(s=>({name:d(String(s?.name??"").padEnd(i," ")),type:d(String(s?.type??"")),description:d(String(s?.description??"")),default:d(s?.default===void 0?"-":String(s.default)),choices:d(Array.isArray(s?.choices)?s.choices.join(", "):s?.choices??"-")})));});}function Se(e){e.command("whoami").description("Show Jenkins user info for the current token").action(async()=>{let{jenkins:t}=await p(),n=await ie(t),r=n&&typeof n=="object"?n:{value:n},o=(l,c)=>{let m=l.length;if(m>=c)return l;let f=c-m,b=Math.floor(f/2),y=f-b;return `${" ".repeat(b)}${l}${" ".repeat(y)}`},a=r.name??r.fullName??r.id??"",i=a==null?"":String(a),s=Math.max(20,i.length),u={};u.name=d(o(i,s));for(let l of Object.keys(r).sort((c,m)=>c.localeCompare(m,"en"))){if(l==="name")continue;let c=r[l],m=l.toLowerCase();if((m==="url"||m.endsWith("url")||m.includes("url"))&&(typeof c=="string"||typeof c=="number")){u[l]=k(String(c));continue}let b=c==null?"":typeof c=="object"?JSON.stringify(c):String(c);u[l]=d(b);}console.table([u]);});}function $e(e){e.command("config").description("Read Jenkins job configuration").command("read").description("Read job configuration").option("-j, --job <job>","Specify job").option("-f, --format <format>","Output format: xml or json","xml").action(async n=>{let{config:r,jenkins:o}=await p(),a=h(r.job,n.job),i=String(n.format??"xml").toLowerCase();if(i!=="xml"&&i!=="json")throw new Error(`Invalid format: ${n.format}. Expected: xml or json`);let s=await le(o,a);if(i==="xml"){process.stdout.write(s);return}let l=new XMLParser({ignoreAttributes:!1,attributeNamePrefix:"@_"}).parse(s);console.log(JSON.stringify(l,null,2));});}function Je(e){let t=e.command("job").description("Job operations"),n=(r,o)=>{let a=String(o??"").trim();if(!a)return !0;if(!/[*?]/.test(a))return r.includes(a);let u=`^${a.replace(/[$()*+.?[\\\]^{|}]/g,"\\$&").replace(/\\\*/g,".*").replace(/\\\?/g,".")}$`;try{return new RegExp(u).test(r)}catch{return r.includes(a)}};t.command("list").alias("ls").description("List all jobs").option("--search <keyword>","Filter by name (supports glob)").action(async r=>{let{jenkins:o}=await p(),a=await se(o),i=(r.search??"").trim(),s=i?a.filter(c=>n(String(c.name??""),i)):a;s.sort((c,m)=>String(c?.name??"").localeCompare(String(m?.name??""),"en",{sensitivity:"base"}));let u=Math.max(0,...s.map(c=>String(c?.name??"").length)),l=Math.max(0,...s.map(c=>String(c?.url??"").length));console.table((s??[]).map(c=>({name:d(String(c.name??"").padEnd(u," ")),color:Q(c.color),url:k(String(c.url??"").padEnd(l," "))})));}),t.command("info").description("Show job info").option("-j, --job <job>","Specify job").option("--json","Output raw JSON").action(async r=>{let{config:o,jenkins:a}=await p(),i=h(o.job,r.job),s=await q(a,i);if(r.json){console.log(JSON.stringify(s,null,2));return}let u=s?.lastBuild,l=s?.lastCompletedBuild,c=Array.isArray(s?.healthReport)?s.healthReport:[];console.table([{name:d(String(s?.name??"")),url:k(String(s?.url??"")),color:Q(s?.color),buildable:s?.buildable,inQueue:s?.inQueue,nextBuildNumber:s?.nextBuildNumber,healthScore:c[0]?.score??"-",lastBuild:d(u?.number?`#${u.number}`:"-"),lastResult:E(u?.result,u?.building),lastDurationS:u?.duration===void 0?"-":Number((Number(u.duration)/1e3).toFixed(3)),lastDate:d(u?.timestamp?J(Number(u.timestamp)):"-"),lastCompleted:d(l?.number?`#${l.number}`:"-"),lastCompletedResult:E(l?.result,!1),lastCompletedDate:d(l?.timestamp?J(Number(l.timestamp)):"-")}]);});}function tt(e){return e.split(",").map(t=>t.trim()).filter(Boolean)}function nt(e){let t=e.indexOf("=");if(t<=0)throw new Error(`Invalid --param: "${e}". Expected: key=value`);let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();if(!n)throw new Error(`Invalid --param: "${e}". Key is empty`);return {key:n,value:r}}function Re(e){e.command("trigger").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,n)=>n.concat(tt(t)),[]).option("--param <key=value>","Extra parameters (repeatable, e.g., --param foo=bar)",(t,n)=>n.concat(t),[]).option("-j, --job <job>","Specify job").action(async t=>{let{config:n,jenkins:r}=await p(),o=h(n.job,t.job),a=String(t.branch??"").trim();if(!a)throw new Error("branch is required");let i=(t.mode??[]).map(String).map(f=>f.trim()).filter(Boolean),s=Array.from(new Set(i));if(s.length===0)throw new Error("mode is required. Example: jenkins-cli trigger -b origin/develop -m dev -m uat");let u={};for(let f of t.param??[]){let{key:b,value:y}=nt(String(f));u[b]=y;}console.log();let l=!1,c=()=>{l||(l=!0,console.log());},m=s.map(async f=>{let b=We(`Triggering build for ${g.yellow(f)}...`).start();try{let y=await I(r,o,{...u,branch:a,mode:f});c(),b.succeed(`${g.green(f)} - Triggered! Queue: ${y}`);}catch(y){throw c(),b.fail(`${g.red(f)} - ${y.message}`),y}});try{await Promise.all(m);}catch{console.log(g.bold.red(`
35
+ `)),process.exit(1);}}function y(n,e){return (e??"").trim()||n}function x(n,e){let t=Number(n);if(!Number.isInteger(t)||t<0)throw new p(`${e} must be a non-negative integer.`,{hint:`Provide a valid ${e}.`,example:`jenkins-cli console ${e==="id"?"123":"last -t 100"}`});return t}function K(n,e){let t=String(e??"").trim();if(!t)return !0;if(!/[*?]/.test(t))return n.includes(t);let s=`^${t.replace(/[$()*+.?[\\\]^{|}]/g,"\\$&").replace(/\\\*/g,".*").replace(/\\\?/g,".")}$`;try{return new RegExp(s).test(n)}catch{return n.includes(t)}}function Ae(n){let e=n.command("queue").description("Operations for the build queue");e.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 t=>{let{config:r,jenkins:o}=await g(),s=t.job?y(r.job,t.job):void 0,i=await A(o,s);console.table((i??[]).map(a=>({id:a.id,job:a.task?.name,why:a.why})));}),e.command("cancel").description("Cancel a queued build item").argument("<id...>","Queue id(s)").action(async t=>{let{jenkins:r}=await g(),o=Array.isArray(t)?t:[String(t??"")],s=await Promise.all(o.map(async a=>{let c=x(String(a),"id");try{return await I(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(b.green(`Cancelled ${s.length} queue item(s).`));return}console.log(b.yellow(`Cancelled ${s.length-i.length} item(s), failed ${i.length} item(s).`));for(let a of i)console.log(b.red(`- ${a.id}: ${a.message??"Cancel failed"}`));});}function f(n){return {[ft.inspect.custom]:()=>n}}function ee(n,e){return String(n??"").padEnd(e," ")}function k(n){return Math.max(0,...n.map(e=>String(e??"").length))}function v(n,e){return f(ee(n,e))}function C(n){let e=String(n??""),t=e.trim();if(!t)return f(b.gray("-"));let r=s=>f(s),o=t.toLowerCase();if(o.startsWith("http://")||o.startsWith("https://"))try{let i=(new URL(t).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?b.cyanBright(e):b.hex("#4EA1FF")(e))}catch{return r(b.hex("#4EA1FF")(e))}return o.startsWith("ws://")||o.startsWith("wss://")?r(b.cyan(e)):o.startsWith("ssh://")||o.startsWith("git+ssh://")||o.startsWith("git@")?r(b.magenta(e)):o.startsWith("file://")?r(b.yellow(e)):o.startsWith("mailto:")?r(b.green(e)):o.startsWith("javascript:")||o.startsWith("data:")?r(b.red(e)):t.startsWith("/")||t.startsWith("./")||t.startsWith("../")?r(b.cyan(e)):/^[a-z0-9.-]+(?::\d+)?(\/|$)/i.test(t)?r(b.blue(e)):r(e)}function S(n){let e=new Date(n),t=r=>String(r).padStart(2,"0");return `${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())} ${t(e.getHours())}:${t(e.getMinutes())}:${t(e.getSeconds())}`}function O(n,e){if(e===!0)return f(b.cyan("BUILDING"));let t=String(n??"").toUpperCase();return f(t?t==="SUCCESS"?b.green(t):t==="ABORTED"?b.gray(t):t==="FAILURE"?b.red(t):t==="UNSTABLE"?b.yellow(t):t==="NOT_BUILT"?b.gray(t):t:"-")}function te(n){let e=String(n??"");if(!e)return f("-");let t=e.endsWith("_anime"),r=t?e.slice(0,-6):e,o=(()=>{switch(r){case"blue":return t?b.blueBright(e):b.blue(e);case"red":return t?b.redBright(e):b.red(e);case"yellow":return t?b.yellowBright(e):b.yellow(e);case"aborted":return b.gray(e);case"disabled":case"notbuilt":case"grey":case"gray":return b.gray(e);default:return e}})();return f(o)}function Be(n){let e=Object.entries(n??{}).filter(([r])=>r);return e.length?(e.sort(([r],[o])=>r.localeCompare(o,"en",{sensitivity:"base"})),e.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 Ee(n){let e=n.command("builds").description("Build operations");e.option("-j, --job <job>","Specify job").option("-n, --limit <n>","Limit","20").action(async t=>{let{config:r,jenkins:o}=await g(),s=y(r.job,t.job),a=(await ye(o,s,{limit:Number(t.limit)})).map(l=>({number:l.number,result:O(l.result,l.building),building:l.building,"duration(s)":Number((Number(l.duration??0)/1e3).toFixed(3)),date:f(S(Number(l.timestamp??0))),parameters:Be(l.parameters),url:C(String(l.url??""))})),c=k(a.map(l=>l.parameters));console.table(a.map(l=>({...l,parameters:v(l.parameters,c)})));}),e.command("active").description("List active builds").option("-j, --job <job>","Specify job").option("-a, --all","Query all running builds on Jenkins").action(async t=>{let{config:r,jenkins:o}=await g(),i=((t.all?await W(o):await L(o,y(r.job,t.job)))??[]).map(c=>({...t.all?{job:f(String(c.job??""))}:{},number:c.number,date:f(c.timestamp?S(Number(c.timestamp)):"-"),parameters:Be(c.parameters),url:C(String(c.url??""))})),a=k(i.map(c=>c.parameters));console.table(i.map(c=>({...c,parameters:v(c.parameters,a)})));});}function gt(n){let e=String(n?.authorEmail??"").trim(),t=e?e.split("@")[0]??"":"";return t||e}function Le(n){let e=[];for(let t of n){let r=Number(t?.number),o=Number.isInteger(r)?`#${r}`:f("-"),s=t?.timestamp?S(Number(t.timestamp)):"-",i=t?.changeSet?.items??[];if(!i.length){e.push({build:o,date:f(s),author:f("-"),message:f("-")});continue}for(let a of i){let c=gt(a),l=String(a?.msg??"").trim();e.push({build:o,date:f(s),author:f(c||"-"),message:f(l||"-")});}}return e}function Ie(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(e,t)=>{let{config:r,jenkins:o}=await g(),s=y(r.job,t.job);if(e){let c=x(e,"id"),l=await je(o,s,c);if(t.raw){console.log(JSON.stringify({build:l.number,changeSet:l.changeSet??{}},null,2));return}console.table(Le([l]));return}let i=Math.max(1,x(t.limit,"limit")),a=await we(o,s,{limit:i});if(t.raw){console.log(JSON.stringify(a.map(c=>({build:c.number,changeSet:c.changeSet??{}})),null,2));return}console.table(Le(a));});}function Ue(){let n=process.argv,e=n.findIndex(r=>r==="-j"||r==="--job");if(e<0)return;let t=n[e+1];return !t||t.startsWith("-")?"":t}function qe(n){let e=n.command("console").description("Fetch build console log"),t=async(r,o,s)=>{let{jenkins:i}=await g(),a=await xe(i,r,o);if(s.tail){let c=x(s.tail,"tail"),l=a.split(`
36
+ `);console.log(l.slice(Math.max(0,l.length-c)).join(`
37
+ `));return}process.stdout.write(a);};e.argument("<id>","Build number").option("-j, --job <job>","Specify job").option("-t, --tail <n>","Only output the last N lines").action(async(r,o)=>{let{config:s}=await g(),i=o.job??Ue();if(i==="")throw new p("Job is required.",{hint:"Provide a job name after -j/--job.",example:"jenkins-cli console 123 -j my-job"});let a=y(s.job,i),c=x(r,"id");await t(a,c,o);}),e.command("last").description("Fetch the latest build log").option("-j, --job <job>","Specify job").option("-s, --status <status>","success | failed | any","any").option("-t, --tail <n>","Only output the last N lines").action(async r=>{let{config:o,jenkins:s}=await g(),i=r.job??Ue();if(i==="")throw new p("Job is required.",{hint:"Provide a job name after -j/--job.",example:"jenkins-cli console last -j my-job -s success"});let a=y(o.job,i),c=String(r.status??"any").toLowerCase();if(!["any","success","failed"].includes(c))throw new p(`Invalid status: ${r.status}.`,{hint:"Use success | failed | any.",example:"jenkins-cli console last -s success"});let l=await Q(s,a),u=c==="success"?l?.lastSuccessfulBuild:c==="failed"?l?.lastFailedBuild:l?.lastBuild,m=Number(u?.number);if(!m){let d=c==="success"?"successful":c==="failed"?"failed":"last";throw new p(`No ${d} build found for job: ${a}`,{hint:"Check the job name or status filter.",example:"jenkins-cli console last -j my-job -s any"})}await t(a,m,r);});}function Oe(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(e,t)=>{let{config:r,jenkins:o}=await g(),s=y(r.job,t.job);if(t.ALL){let[i,a]=await Promise.all([A(o),W(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 I(o,u);for(let u of l)await U(o,u.job,u.number);console.log(b.green(`Requested: cancelled ${c.length} queue item(s), stopped ${l.length} running build(s).`));return}if(t.all){let[i,a]=await Promise.all([A(o,s),L(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 I(o,u);for(let u of l)await U(o,s,u);console.log(b.green(`Requested: cancelled ${c.length} queue item(s), stopped ${l.length} running build(s).`));return}if(!e){console.log(b.red("Missing build id. Provide <id> or use -a/--all."));return}await U(o,s,x(e,"id")),console.log(b.green("Stop requested"));});}function Fe(n){n.command("params").description("Show job parameter definitions").option("-j, --job <job>","Specify job").action(async e=>{let{config:t,jenkins:r}=await g(),o=y(t.job,e.job),s=await ke(r,o),i=k(s.map(a=>a?.name));console.table((s??[]).map(a=>({name:v(a?.name??"",i),type:f(String(a?.type??"")),description:f(String(a?.description??"")),default:f(a?.default===void 0?"-":String(a.default)),choices:f(Array.isArray(a?.choices)?a.choices.join(", "):a?.choices??"-")})));});}function Te(n){n.command("me").description("Show Jenkins user info for the current token").option("--raw","Print raw response").action(async e=>{let{jenkins:t}=await g(),r=await he(t);if(e.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,m)=>{let d=u.length;if(d>=m)return u;let h=m-d,w=Math.floor(h/2),B=h-w;return `${" ".repeat(w)}${u}${" ".repeat(B)}`},i=o.name??o.fullName??o.id??"",a=i==null?"":String(i),c=Math.max(20,a.length),l={};l.name=f(s(a,c));for(let u of Object.keys(o).sort((m,d)=>m.localeCompare(d,"en"))){if(u==="name")continue;let m=o[u],d=u.toLowerCase();if((d==="url"||d.endsWith("url")||d.includes("url"))&&(typeof m=="string"||typeof m=="number")){l[u]=C(String(m));continue}let w=m==null?"":typeof m=="object"?JSON.stringify(m):String(m);l[u]=f(w);}console.table([l]);});}function De(n){let e=n.command("config").description("Show Jenkins job configuration");e.command("show").description("Show job configuration").option("-j, --job <job>","Specify job").option("-f, --format <format>","Output format: xml or json","xml").action(async t=>{let{config:r,jenkins:o}=await g(),s=y(r.job,t.job),i=String(t.format??"xml").toLowerCase();if(i!=="xml"&&i!=="json")throw new p(`Invalid format: ${t.format}.`,{hint:"Use xml or json.",example:"jenkins-cli config show -f json"});let a=await X(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));}),e.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 t=>{let{config:r,jenkins:o}=await g(),s=String(t.destination??"").trim();if(!s)throw new p("Destination is required.",{hint:"Provide a destination folder with -d or --destination.",example:"jenkins-cli config backup -d ./jenkins-backup"});if(t.all&&t.filter)throw new p("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(t.filter??"").trim(),a=t.all?await q(o):i?(await q(o)).filter(l=>K(String(l.name??""),i)):[{name:y(r.job,t.job)}];if(a.length===0)throw new p(`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 m=await X(o,u),d=R.join(s,u,"config.xml");await promises.mkdir(R.dirname(d),{recursive:!0}),await promises.writeFile(d,m),c.push(d);}console.log(`Backup completed. ${c.length} file(s) saved to ${R.resolve(s)}`);});}function We(n){let e=n.command("job").description("Job operations");e.command("list").alias("ls").description("List all jobs").option("--search <keyword>","Filter by name (supports glob)").action(async t=>{let{jenkins:r}=await g(),o=await q(r),s=(t.search??"").trim(),i=s?o.filter(l=>K(String(l.name??""),s)):o;i.sort((l,u)=>String(l?.name??"").localeCompare(String(u?.name??""),"en",{sensitivity:"base"}));let a=k(i.map(l=>l?.name)),c=k(i.map(l=>l?.url));console.table((i??[]).map(l=>({name:v(l.name??"",a),color:te(l.color),url:C(ee(l.url??"",c))})));}),e.command("info").description("Show job info").option("-j, --job <job>","Specify job").option("--json","Output raw JSON").action(async t=>{let{config:r,jenkins:o}=await g(),s=y(r.job,t.job),i=await Q(o,s);if(t.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:f(String(i?.name??"")),url:C(String(i?.url??"")),color:te(i?.color),buildable:i?.buildable,inQueue:i?.inQueue,nextBuildNumber:i?.nextBuildNumber,healthScore:l[0]?.score??"-",lastBuild:f(a?.number?`#${a.number}`:"-"),lastResult:O(a?.result,a?.building),"lastDuration(s)":a?.duration===void 0?"-":Number((Number(a.duration)/1e3).toFixed(3)),lastDate:f(a?.timestamp?S(Number(a.timestamp)):"-"),lastCompleted:f(c?.number?`#${c.number}`:"-"),lastCompletedResult:O(c?.result,!1),lastCompletedDate:f(c?.timestamp?S(Number(c.timestamp)):"-")}]);});}function yt(n){return n.split(",").map(e=>e.trim()).filter(Boolean)}function wt(n){let e=n.split("=");if(e.length<2)throw new p(`Invalid --param: "${n}".`,{hint:"Use the format key=value.",example:"jenkins-cli build -b origin/main -m dev --param foo=bar"});let t=e[0].trim(),r=e.slice(1).join("=").trim();if(!t)throw new p(`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:t,value:r}}function Me(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)",(e,t)=>t.concat(yt(e)),[]).option("--param <key=value>","Extra parameters (repeatable, e.g., --param foo=bar)",(e,t)=>t.concat(e),[]).option("-j, --job <job>","Specify job").action(async e=>{let{config:t,jenkins:r}=await g(),o=y(t.job,e.job),s=String(e.branch??"").trim();if(!s)throw new p("branch is required.",{hint:"Pass a branch with -b or --branch.",example:"jenkins-cli build -b origin/develop -m dev"});let i=(e.mode??[]).map(String).map(d=>d.trim()).filter(Boolean),a=Array.from(new Set(i));if(a.length===0)throw new p("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 d of e.param??[]){let{key:h,value:w}=wt(String(d));c[h]=w;}console.log();let l=!1,u=()=>{l||(l=!0,console.log());},m=a.map(async d=>{let h=it(`Triggering build for ${b.yellow(d)}...`).start();try{let w=await M(r,o,{...c,branch:s,mode:d});u(),h.succeed(`${b.green(d)} - Triggered! Queue: ${w}`);}catch(w){throw u(),h.fail(`${b.red(d)} - ${w.message}`),w}});try{await Promise.all(m);}catch{console.log(b.bold.red(`
35
38
  \u274C Some builds failed. Check the output above.
36
- `)),process.exit(1);}});}function ve(e){je(e),$e(e),Je(e),xe(e),Ce(e),we(e),ke(e),Re(e),Se(e);}program.name("jenkins-cli").description(Y).version(H,"-v, --version").helpOption("-h, --help").configureHelp({sortSubcommands:!0,sortOptions:!0}).action(ye);ve(program);program.parse();
39
+ `)),process.exit(1);}});}function Qe(n){Ee(n),Ie(n),De(n),We(n),qe(n),Fe(n),Ae(n),Oe(n),Me(n),Te(n);}program.name("jenkins-cli").description(ae).version(se,"-v, --version").helpOption("-h, --help").allowExcessArguments(!1).configureHelp({sortSubcommands:!0,sortOptions:!0}).action(Re);Qe(program);async function jt(){try{await program.parseAsync(process.argv);}catch(n){J(n);}}jt();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ts-org/jenkins-cli",
3
- "version": "3.0.3",
3
+ "version": "3.0.4",
4
4
  "description": "Jenkins deployment CLI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -8,13 +8,6 @@
8
8
  "jenkins-cli": "dist/cli.js",
9
9
  "jc": "dist/cli.js"
10
10
  },
11
- "scripts": {
12
- "build": "tsup",
13
- "dev": "NODE_ENV=development tsup --watch",
14
- "prepublishOnly": "npm run build",
15
- "link:test": "npm run build && npm link",
16
- "format": "eslint . --fix && prettier . --write"
17
- },
18
11
  "keywords": [
19
12
  "jenkins",
20
13
  "cli",
@@ -66,5 +59,11 @@
66
59
  "directories": {
67
60
  "doc": "docs"
68
61
  },
69
- "types": "./dist/index.d.ts"
70
- }
62
+ "types": "./dist/index.d.ts",
63
+ "scripts": {
64
+ "build": "tsup",
65
+ "dev": "NODE_ENV=development tsup --watch",
66
+ "link:test": "npm run build && npm link",
67
+ "format": "eslint . --fix && prettier . --write"
68
+ }
69
+ }
@@ -63,4 +63,4 @@
63
63
  },
64
64
  "required": ["apiToken", "job", "modes"],
65
65
  "additionalProperties": false
66
- }
66
+ }