@daghis/teamcity-mcp 1.10.6 → 1.10.8

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.
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "1.10.6"
2
+ ".": "1.10.8"
3
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.10.8](https://github.com/Daghis/teamcity-mcp/compare/teamcity-mcp-v1.10.7...teamcity-mcp-v1.10.8) (2025-10-07)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **teamcity:** send snapshot options separately (238) ([fc9b313](https://github.com/Daghis/teamcity-mcp/commit/fc9b31379feccded78db5a35e1dc6f5ad13dccbd))
9
+ * **teamcity:** send snapshot options separately (238) ([6af8ea6](https://github.com/Daghis/teamcity-mcp/commit/6af8ea63dcc7dfae915a55287f3e1bc31e0a5c03))
10
+
11
+ ## [1.10.7](https://github.com/Daghis/teamcity-mcp/compare/teamcity-mcp-v1.10.6...teamcity-mcp-v1.10.7) (2025-10-06)
12
+
13
+
14
+ ### Bug Fixes
15
+
16
+ * **teamcity:** serialize snapshot dependencies as xml ([#235](https://github.com/Daghis/teamcity-mcp/issues/235)) ([#236](https://github.com/Daghis/teamcity-mcp/issues/236)) ([9cec149](https://github.com/Daghis/teamcity-mcp/commit/9cec14934783f135b408211fefa41ba6a38391c8))
17
+
3
18
  ## [1.10.6](https://github.com/Daghis/teamcity-mcp/compare/teamcity-mcp-v1.10.5...teamcity-mcp-v1.10.6) (2025-10-04)
4
19
 
5
20
 
package/dist/index.js CHANGED
@@ -2321,6 +2321,12 @@ var JSON_HEADERS2 = {
2321
2321
  Accept: "application/json"
2322
2322
  }
2323
2323
  };
2324
+ var XML_HEADERS = {
2325
+ headers: {
2326
+ "Content-Type": "application/xml",
2327
+ Accept: "application/json"
2328
+ }
2329
+ };
2324
2330
  var JSON_GET_HEADERS2 = {
2325
2331
  headers: {
2326
2332
  Accept: "application/json"
@@ -2336,6 +2342,13 @@ var defaultTypeFor = (dependencyType) => {
2336
2342
  return void 0;
2337
2343
  }
2338
2344
  };
2345
+ var SNAPSHOT_DEPENDENCY_OPTION_KEYS = /* @__PURE__ */ new Set([
2346
+ "run-build-on-the-same-agent",
2347
+ "sync-revisions",
2348
+ "take-successful-builds-only",
2349
+ "take-started-build-with-same-revisions",
2350
+ "do-not-run-new-build-if-there-is-a-suitable-one"
2351
+ ]);
2339
2352
  var toStringRecord2 = (input) => {
2340
2353
  if (!input) {
2341
2354
  return {};
@@ -2375,6 +2388,30 @@ var recordToProperties2 = (record) => {
2375
2388
  property: entries.map(([name, value]) => ({ name, value }))
2376
2389
  };
2377
2390
  };
2391
+ var optionsToRecord = (options) => {
2392
+ if (!options) {
2393
+ return {};
2394
+ }
2395
+ const optionEntries = options?.option;
2396
+ const collection = Array.isArray(optionEntries) ? optionEntries : optionEntries != null ? [optionEntries] : [];
2397
+ const map = {};
2398
+ for (const item of collection) {
2399
+ if (!item?.name) {
2400
+ continue;
2401
+ }
2402
+ map[item.name] = item.value != null ? String(item.value) : "";
2403
+ }
2404
+ return map;
2405
+ };
2406
+ var recordToOptions = (record) => {
2407
+ const entries = Object.entries(record);
2408
+ if (entries.length === 0) {
2409
+ return void 0;
2410
+ }
2411
+ return {
2412
+ option: entries.map(([name, value]) => ({ name, value }))
2413
+ };
2414
+ };
2378
2415
  var mergeRecords2 = (base, override) => {
2379
2416
  const merged = { ...base };
2380
2417
  for (const [key, value] of Object.entries(override)) {
@@ -2382,6 +2419,109 @@ var mergeRecords2 = (base, override) => {
2382
2419
  }
2383
2420
  return merged;
2384
2421
  };
2422
+ var escapeXml = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
2423
+ var attributesToString = (attributes) => {
2424
+ const parts = Object.entries(attributes).filter(([, value]) => value !== void 0).map(([key, value]) => `${key}="${escapeXml(value)}"`);
2425
+ return parts.length > 0 ? ` ${parts.join(" ")}` : "";
2426
+ };
2427
+ var propertiesToXml = (properties) => {
2428
+ if (!properties) {
2429
+ return void 0;
2430
+ }
2431
+ const entries = properties.property;
2432
+ const list = Array.isArray(entries) ? entries : entries != null ? [entries] : [];
2433
+ if (list.length === 0) {
2434
+ return void 0;
2435
+ }
2436
+ const nodes = list.filter((item) => item?.name).map((item) => {
2437
+ const name = item?.name ?? "";
2438
+ const value = item?.value != null ? String(item.value) : "";
2439
+ return `<property name="${escapeXml(name)}" value="${escapeXml(value)}"/>`;
2440
+ });
2441
+ if (nodes.length === 0) {
2442
+ return void 0;
2443
+ }
2444
+ return `<properties>${nodes.join("")}</properties>`;
2445
+ };
2446
+ var optionsToXml = (options) => {
2447
+ if (!options) {
2448
+ return void 0;
2449
+ }
2450
+ const entries = options.option;
2451
+ const list = Array.isArray(entries) ? entries : entries != null ? [entries] : [];
2452
+ if (list.length === 0) {
2453
+ return void 0;
2454
+ }
2455
+ const nodes = list.filter((item) => item?.name).map((item) => {
2456
+ const name = item?.name ?? "";
2457
+ const value = item?.value != null ? String(item.value) : "";
2458
+ return `<option name="${escapeXml(name)}" value="${escapeXml(value)}"/>`;
2459
+ });
2460
+ if (nodes.length === 0) {
2461
+ return void 0;
2462
+ }
2463
+ return `<options>${nodes.join("")}</options>`;
2464
+ };
2465
+ var sourceBuildTypeToXml = (source) => {
2466
+ if (!source || typeof source !== "object") {
2467
+ return void 0;
2468
+ }
2469
+ const { id, name } = source;
2470
+ if (!id) {
2471
+ return void 0;
2472
+ }
2473
+ const attributes = {
2474
+ id,
2475
+ name
2476
+ };
2477
+ return `<source-buildType${attributesToString(attributes)}/>`;
2478
+ };
2479
+ var dependencyToXml = (dependencyType, payload) => {
2480
+ const root = dependencyType === "artifact" ? "artifact-dependency" : "snapshot-dependency";
2481
+ const normalizeTypeAttribute = (value) => {
2482
+ if (!value) {
2483
+ return void 0;
2484
+ }
2485
+ if (dependencyType === "snapshot" && value === "snapshotDependency") {
2486
+ return "snapshot_dependency";
2487
+ }
2488
+ if (dependencyType === "artifact" && value === "artifactDependency") {
2489
+ return "artifact_dependency";
2490
+ }
2491
+ return value;
2492
+ };
2493
+ const attributes = {
2494
+ id: typeof payload.id === "string" && payload.id.trim() !== "" ? payload.id : void 0,
2495
+ name: typeof payload.name === "string" && payload.name.trim() !== "" ? payload.name : void 0,
2496
+ type: typeof payload.type === "string" && payload.type.trim() !== "" ? normalizeTypeAttribute(payload.type) : void 0,
2497
+ disabled: typeof payload.disabled === "boolean" ? payload.disabled ? "true" : "false" : void 0,
2498
+ inherited: typeof payload.inherited === "boolean" ? payload.inherited ? "true" : "false" : void 0
2499
+ };
2500
+ const fragments = [];
2501
+ const sourceBuildTypeXml = sourceBuildTypeToXml(
2502
+ payload["source-buildType"]
2503
+ );
2504
+ if (sourceBuildTypeXml) {
2505
+ fragments.push(sourceBuildTypeXml);
2506
+ }
2507
+ const propertiesXml = propertiesToXml(payload.properties);
2508
+ if (propertiesXml) {
2509
+ fragments.push(propertiesXml);
2510
+ }
2511
+ const optionsXml = optionsToXml(payload.options);
2512
+ if (optionsXml) {
2513
+ fragments.push(optionsXml);
2514
+ }
2515
+ return `<${root}${attributesToString(attributes)}>${fragments.join("")}</${root}>`;
2516
+ };
2517
+ var prepareArtifactRequest = (payload) => ({
2518
+ body: payload,
2519
+ headers: JSON_HEADERS2
2520
+ });
2521
+ var prepareSnapshotRequest = (payload) => ({
2522
+ body: dependencyToXml("snapshot", payload),
2523
+ headers: XML_HEADERS
2524
+ });
2385
2525
  var BuildDependencyManager = class {
2386
2526
  constructor(client) {
2387
2527
  this.client = client;
@@ -2436,36 +2576,40 @@ var BuildDependencyManager = class {
2436
2576
  }
2437
2577
  async createDependency(dependencyType, buildTypeId, payload) {
2438
2578
  if (dependencyType === "artifact") {
2579
+ const { body: body2, headers: headers2 } = prepareArtifactRequest(payload);
2439
2580
  return this.client.modules.buildTypes.addArtifactDependencyToBuildType(
2440
2581
  buildTypeId,
2441
2582
  void 0,
2442
- payload,
2443
- JSON_HEADERS2
2583
+ body2,
2584
+ headers2
2444
2585
  );
2445
2586
  }
2587
+ const { body, headers } = prepareSnapshotRequest(payload);
2446
2588
  return this.client.modules.buildTypes.addSnapshotDependencyToBuildType(
2447
2589
  buildTypeId,
2448
2590
  void 0,
2449
- payload,
2450
- JSON_HEADERS2
2591
+ body,
2592
+ headers
2451
2593
  );
2452
2594
  }
2453
2595
  async replaceDependency(dependencyType, buildTypeId, dependencyId, payload) {
2454
2596
  if (dependencyType === "artifact") {
2597
+ const { body: body2, headers: headers2 } = prepareArtifactRequest(payload);
2455
2598
  return this.client.modules.buildTypes.replaceArtifactDependency(
2456
2599
  buildTypeId,
2457
2600
  dependencyId,
2458
2601
  void 0,
2459
- payload,
2460
- JSON_HEADERS2
2602
+ body2,
2603
+ headers2
2461
2604
  );
2462
2605
  }
2606
+ const { body, headers } = prepareSnapshotRequest(payload);
2463
2607
  return this.client.modules.buildTypes.replaceSnapshotDependency(
2464
2608
  buildTypeId,
2465
2609
  dependencyId,
2466
2610
  void 0,
2467
- payload,
2468
- JSON_HEADERS2
2611
+ body,
2612
+ headers
2469
2613
  );
2470
2614
  }
2471
2615
  async fetchDependency(dependencyType, buildTypeId, dependencyId) {
@@ -2482,7 +2626,7 @@ var BuildDependencyManager = class {
2482
2626
  const response = await this.client.modules.buildTypes.getSnapshotDependency(
2483
2627
  buildTypeId,
2484
2628
  dependencyId,
2485
- "id,type,disabled,properties(property(name,value)),'source-buildType'(id)",
2629
+ "id,type,disabled,properties(property(name,value)),options(option(name,value)),'source-buildType'(id)",
2486
2630
  JSON_GET_HEADERS2
2487
2631
  );
2488
2632
  return response.data;
@@ -2494,9 +2638,42 @@ var BuildDependencyManager = class {
2494
2638
  }
2495
2639
  }
2496
2640
  buildPayload(dependencyType, existing, input) {
2497
- const baseProps = propertiesToRecord2(existing?.properties);
2498
- const mergedProps = mergeRecords2(baseProps, toStringRecord2(input.properties));
2641
+ const existingSnapshot = existing;
2642
+ const baseProperties = propertiesToRecord2(existing?.properties);
2643
+ const inputPropertyRecord = toStringRecord2(input.properties);
2644
+ const inputExplicitOptions = toStringRecord2(input.options);
2645
+ let optionOverrides = {};
2646
+ let propertyOverrides = inputPropertyRecord;
2647
+ let baseOptions = {};
2648
+ if (dependencyType === "snapshot") {
2649
+ baseOptions = optionsToRecord(existingSnapshot?.options);
2650
+ const knownOptionKeys = /* @__PURE__ */ new Set([
2651
+ ...Object.keys(baseOptions),
2652
+ ...Object.keys(inputExplicitOptions)
2653
+ ]);
2654
+ for (const key of SNAPSHOT_DEPENDENCY_OPTION_KEYS) {
2655
+ knownOptionKeys.add(key);
2656
+ }
2657
+ const derivedOptionOverrides = { ...inputExplicitOptions };
2658
+ const derivedPropertyOverrides = {};
2659
+ for (const [key, value] of Object.entries(inputPropertyRecord)) {
2660
+ if (knownOptionKeys.has(key)) {
2661
+ derivedOptionOverrides[key] = value;
2662
+ } else {
2663
+ derivedPropertyOverrides[key] = value;
2664
+ }
2665
+ }
2666
+ optionOverrides = derivedOptionOverrides;
2667
+ propertyOverrides = derivedPropertyOverrides;
2668
+ } else if (Object.keys(inputExplicitOptions).length > 0) {
2669
+ optionOverrides = inputExplicitOptions;
2670
+ }
2671
+ const mergedProps = mergeRecords2(baseProperties, propertyOverrides);
2499
2672
  const properties = recordToProperties2(mergedProps);
2673
+ let mergedOptions = {};
2674
+ if (dependencyType === "snapshot") {
2675
+ mergedOptions = mergeRecords2(baseOptions, optionOverrides);
2676
+ }
2500
2677
  const resolvedType = input.type ?? existing?.type ?? defaultTypeFor(dependencyType);
2501
2678
  const payload = {
2502
2679
  ...existing ?? {},
@@ -2507,6 +2684,16 @@ var BuildDependencyManager = class {
2507
2684
  }
2508
2685
  if (properties) {
2509
2686
  payload.properties = properties;
2687
+ } else {
2688
+ delete payload.properties;
2689
+ }
2690
+ if (dependencyType === "snapshot") {
2691
+ const options = recordToOptions(mergedOptions);
2692
+ if (options) {
2693
+ payload.options = options;
2694
+ } else {
2695
+ delete payload.options;
2696
+ }
2510
2697
  }
2511
2698
  const dependsOn = input.dependsOn ?? existing?.["source-buildType"]?.id;
2512
2699
  if (dependsOn) {
@@ -38706,13 +38893,13 @@ var DEV_TOOLS = [
38706
38893
  buildRequest.properties = propertiesPayload;
38707
38894
  }
38708
38895
  const sendXmlFallback = async (error2) => {
38709
- const escapeXml = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
38710
- const branchPart = branchName ? `<branchName>${escapeXml(branchName)}</branchName>` : "";
38711
- const commentPart = commentText ? `<comment><text>${escapeXml(commentText)}</text></comment>` : "";
38896
+ const escapeXml2 = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
38897
+ const branchPart = branchName ? `<branchName>${escapeXml2(branchName)}</branchName>` : "";
38898
+ const commentPart = commentText ? `<comment><text>${escapeXml2(commentText)}</text></comment>` : "";
38712
38899
  const propertiesPart = propertiesPayload ? `<properties>${propertiesPayload.property.map(
38713
- (prop) => `<property name="${escapeXml(prop.name)}" value="${escapeXml(prop.value)}"/>`
38900
+ (prop) => `<property name="${escapeXml2(prop.name)}" value="${escapeXml2(prop.value)}"/>`
38714
38901
  ).join("")}</properties>` : "";
38715
- const xml = `<?xml version="1.0" encoding="UTF-8"?><build><buildType id="${escapeXml(
38902
+ const xml = `<?xml version="1.0" encoding="UTF-8"?><build><buildType id="${escapeXml2(
38716
38903
  typed.buildTypeId
38717
38904
  )}"/>${branchPart}${commentPart}${propertiesPart}</build>`;
38718
38905
  const response = await adapter.http.post("/app/rest/buildQueue", xml, {
@@ -41445,6 +41632,10 @@ var FULL_MODE_TOOLS = [
41445
41632
  type: "object",
41446
41633
  description: "Dependency properties (e.g. cleanDestinationDirectory, pathRules)"
41447
41634
  },
41635
+ options: {
41636
+ type: "object",
41637
+ description: "Snapshot dependency options (e.g. run-build-on-the-same-agent)"
41638
+ },
41448
41639
  type: {
41449
41640
  type: "string",
41450
41641
  description: "Override dependency type value sent to TeamCity"
@@ -41462,6 +41653,7 @@ var FULL_MODE_TOOLS = [
41462
41653
  dependencyId: import_zod4.z.string().min(1).optional(),
41463
41654
  dependsOn: import_zod4.z.string().min(1).optional(),
41464
41655
  properties: import_zod4.z.record(import_zod4.z.string(), propertyValue).optional(),
41656
+ options: import_zod4.z.record(import_zod4.z.string(), propertyValue).optional(),
41465
41657
  type: import_zod4.z.string().min(1).optional(),
41466
41658
  disabled: import_zod4.z.boolean().optional()
41467
41659
  }).superRefine((value, ctx) => {
@@ -41493,6 +41685,7 @@ var FULL_MODE_TOOLS = [
41493
41685
  dependencyType: typed.dependencyType,
41494
41686
  dependsOn: typed.dependsOn,
41495
41687
  properties: typed.properties,
41688
+ options: typed.options,
41496
41689
  type: typed.type,
41497
41690
  disabled: typed.disabled
41498
41691
  });
@@ -41511,6 +41704,7 @@ var FULL_MODE_TOOLS = [
41511
41704
  dependencyType: typed.dependencyType,
41512
41705
  dependsOn: typed.dependsOn,
41513
41706
  properties: typed.properties,
41707
+ options: typed.options,
41514
41708
  type: typed.type,
41515
41709
  disabled: typed.disabled
41516
41710
  });