@daghis/teamcity-mcp 1.9.1 → 1.9.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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.9.3](https://github.com/Daghis/teamcity-mcp/compare/v1.9.2...v1.9.3) (2025-09-21)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **teamcity:** resolve nested artifact downloads ([#188](https://github.com/Daghis/teamcity-mcp/issues/188)) ([e309b90](https://github.com/Daghis/teamcity-mcp/commit/e309b90de42fe121f072fe5b549ab25df3a91aaf))
9
+
10
+ ## [1.9.2](https://github.com/Daghis/teamcity-mcp/compare/v1.9.1...v1.9.2) (2025-09-21)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **teamcity:** restore artifact rules update compatibility ([#185](https://github.com/Daghis/teamcity-mcp/issues/185)) ([1d67268](https://github.com/Daghis/teamcity-mcp/commit/1d67268e6ee837db38ab9be27a94a5f3e072ab83))
16
+
3
17
  ## [1.9.1](https://github.com/Daghis/teamcity-mcp/compare/v1.9.0...v1.9.1) (2025-09-20)
4
18
 
5
19
 
package/dist/index.js CHANGED
@@ -1216,26 +1216,72 @@ var ArtifactManager = class _ArtifactManager {
1216
1216
  }
1217
1217
  return payload;
1218
1218
  }
1219
- parseArtifacts(data, buildId, includeNested, baseUrl) {
1219
+ parseArtifacts(data, buildId, includeNested, baseUrl, parentSegments = []) {
1220
1220
  const artifacts = [];
1221
1221
  const files = data.file ?? [];
1222
1222
  for (const file of files) {
1223
- if (file.children && includeNested) {
1224
- const nested = this.parseArtifacts(file.children, buildId, includeNested, baseUrl);
1225
- artifacts.push(...nested);
1226
- } else if (!file.children) {
1227
- artifacts.push({
1228
- name: file.name ?? "",
1229
- path: file.fullName ?? file.name ?? "",
1230
- size: file.size ?? 0,
1231
- modificationTime: file.modificationTime ?? "",
1232
- downloadUrl: `${baseUrl}/app/rest/builds/id:${buildId}/artifacts/content/${file.fullName ?? file.name ?? ""}`,
1233
- isDirectory: false
1234
- });
1235
- }
1223
+ const pathSegments = this.buildArtifactSegments(file, parentSegments);
1224
+ const resolvedPath = pathSegments.join("/");
1225
+ const isDirectory = Boolean(file.children);
1226
+ if (isDirectory) {
1227
+ if (includeNested && file.children) {
1228
+ const nested = this.parseArtifacts(
1229
+ file.children,
1230
+ buildId,
1231
+ includeNested,
1232
+ baseUrl,
1233
+ pathSegments
1234
+ );
1235
+ artifacts.push(...nested);
1236
+ }
1237
+ continue;
1238
+ }
1239
+ if (!resolvedPath) {
1240
+ continue;
1241
+ }
1242
+ artifacts.push({
1243
+ name: file.name ?? pathSegments[pathSegments.length - 1] ?? "",
1244
+ path: resolvedPath,
1245
+ size: file.size ?? 0,
1246
+ modificationTime: file.modificationTime ?? "",
1247
+ downloadUrl: `${baseUrl}/app/rest/builds/id:${buildId}/artifacts/content/${this.encodeArtifactPath(pathSegments)}`,
1248
+ isDirectory: false
1249
+ });
1236
1250
  }
1237
1251
  return artifacts;
1238
1252
  }
1253
+ buildArtifactSegments(file, parentSegments) {
1254
+ const fullName = typeof file.fullName === "string" ? file.fullName : void 0;
1255
+ const name = typeof file.name === "string" ? file.name : void 0;
1256
+ const segmentsFromFullName = fullName ? fullName.split("/").filter((segment) => segment.length > 0) : [];
1257
+ if (segmentsFromFullName.length === 0) {
1258
+ if (name && name.length > 0) {
1259
+ return [...parentSegments, name];
1260
+ }
1261
+ return [...parentSegments];
1262
+ }
1263
+ if (parentSegments.length === 0) {
1264
+ return segmentsFromFullName;
1265
+ }
1266
+ if (this.segmentsStartWithParent(segmentsFromFullName, parentSegments)) {
1267
+ return segmentsFromFullName;
1268
+ }
1269
+ return [...parentSegments, ...segmentsFromFullName];
1270
+ }
1271
+ segmentsStartWithParent(segments, parent) {
1272
+ if (parent.length === 0 || segments.length < parent.length) {
1273
+ return false;
1274
+ }
1275
+ for (let i = 0; i < parent.length; i += 1) {
1276
+ if (segments[i] !== parent[i]) {
1277
+ return false;
1278
+ }
1279
+ }
1280
+ return true;
1281
+ }
1282
+ encodeArtifactPath(segments) {
1283
+ return segments.map((segment) => encodeURIComponent(segment)).join("/");
1284
+ }
1239
1285
  ensureBinaryBuffer(payload) {
1240
1286
  if (Buffer.isBuffer(payload)) {
1241
1287
  return payload;
@@ -1346,6 +1392,38 @@ var ArtifactManager = class _ArtifactManager {
1346
1392
  };
1347
1393
 
1348
1394
  // src/teamcity/build-configuration-update-manager.ts
1395
+ var ARTIFACT_RULES_SETTINGS_FIELD = "settings/artifactRules";
1396
+ var ARTIFACT_RULES_LEGACY_FIELD = "artifactRules";
1397
+ var isArtifactRulesRetryableError = (error2) => {
1398
+ if (error2 == null || typeof error2 !== "object") return false;
1399
+ if (!("response" in error2)) return false;
1400
+ const response = error2.response;
1401
+ const status = response?.status;
1402
+ return status === 400 || status === 404;
1403
+ };
1404
+ var setArtifactRulesWithFallback = async (api, buildTypeId, artifactRules) => {
1405
+ try {
1406
+ await api.setBuildTypeField(buildTypeId, ARTIFACT_RULES_SETTINGS_FIELD, artifactRules);
1407
+ } catch (err) {
1408
+ if (!isArtifactRulesRetryableError(err)) {
1409
+ throw err;
1410
+ }
1411
+ const status = err.response?.status;
1412
+ debug("Retrying artifact rules update via legacy field", {
1413
+ buildTypeId,
1414
+ status
1415
+ });
1416
+ try {
1417
+ await api.setBuildTypeField(buildTypeId, ARTIFACT_RULES_LEGACY_FIELD, artifactRules);
1418
+ } catch (fallbackError) {
1419
+ debug("Legacy artifact rules update failed", {
1420
+ buildTypeId,
1421
+ status: fallbackError.response?.status
1422
+ });
1423
+ throw fallbackError;
1424
+ }
1425
+ }
1426
+ };
1349
1427
  var BuildConfigurationUpdateManager = class {
1350
1428
  client;
1351
1429
  constructor(client) {
@@ -1555,6 +1633,14 @@ var BuildConfigurationUpdateManager = class {
1555
1633
  }
1556
1634
  if (settings.length > 0) {
1557
1635
  for (const setting of settings) {
1636
+ if (setting.name === "artifactRules") {
1637
+ await setArtifactRulesWithFallback(
1638
+ this.client.modules.buildTypes,
1639
+ currentConfig.id,
1640
+ setting.value
1641
+ );
1642
+ continue;
1643
+ }
1558
1644
  await this.client.modules.buildTypes.setBuildTypeField(
1559
1645
  currentConfig.id,
1560
1646
  `settings/${setting.name}`,
@@ -40100,9 +40186,9 @@ var FULL_MODE_TOOLS = [
40100
40186
  );
40101
40187
  }
40102
40188
  if (typedArgs.artifactRules !== void 0) {
40103
- await adapter.modules.buildTypes.setBuildTypeField(
40189
+ await setArtifactRulesWithFallback(
40190
+ adapter.modules.buildTypes,
40104
40191
  typedArgs.buildTypeId,
40105
- "settings/artifactRules",
40106
40192
  typedArgs.artifactRules
40107
40193
  );
40108
40194
  }
@@ -40123,9 +40209,9 @@ var FULL_MODE_TOOLS = [
40123
40209
  );
40124
40210
  }
40125
40211
  if (typedArgs.artifactRules !== void 0) {
40126
- await adapter.modules.buildTypes.setBuildTypeField(
40212
+ await setArtifactRulesWithFallback(
40213
+ adapter.modules.buildTypes,
40127
40214
  typedArgs.buildTypeId,
40128
- "settings/artifactRules",
40129
40215
  typedArgs.artifactRules
40130
40216
  );
40131
40217
  }