@mcp-consultant-tools/azure-devops 34.0.0 → 35.0.0-beta.2

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.
Files changed (83) hide show
  1. package/build/cli/commands/build-commands.d.ts.map +1 -1
  2. package/build/cli/commands/build-commands.js +27 -0
  3. package/build/cli/commands/build-commands.js.map +1 -1
  4. package/build/cli/commands/git-commands.d.ts +7 -0
  5. package/build/cli/commands/git-commands.d.ts.map +1 -0
  6. package/build/cli/commands/git-commands.js +68 -0
  7. package/build/cli/commands/git-commands.js.map +1 -0
  8. package/build/cli/commands/index.d.ts +1 -0
  9. package/build/cli/commands/index.d.ts.map +1 -1
  10. package/build/cli/commands/index.js +3 -0
  11. package/build/cli/commands/index.js.map +1 -1
  12. package/build/cli/commands/variable-group-commands.d.ts +1 -1
  13. package/build/cli/commands/variable-group-commands.d.ts.map +1 -1
  14. package/build/cli/commands/variable-group-commands.js +86 -1
  15. package/build/cli/commands/variable-group-commands.js.map +1 -1
  16. package/build/context-factory.d.ts.map +1 -1
  17. package/build/context-factory.js +3 -1
  18. package/build/context-factory.js.map +1 -1
  19. package/build/services/build-issues.d.ts +66 -0
  20. package/build/services/build-issues.d.ts.map +1 -0
  21. package/build/services/build-issues.js +70 -0
  22. package/build/services/build-issues.js.map +1 -0
  23. package/build/services/build-service.d.ts +6 -0
  24. package/build/services/build-service.d.ts.map +1 -1
  25. package/build/services/build-service.js +24 -0
  26. package/build/services/build-service.js.map +1 -1
  27. package/build/services/git-service.d.ts +97 -0
  28. package/build/services/git-service.d.ts.map +1 -0
  29. package/build/services/git-service.js +123 -0
  30. package/build/services/git-service.js.map +1 -0
  31. package/build/services/index.d.ts +1 -0
  32. package/build/services/index.d.ts.map +1 -1
  33. package/build/services/index.js +1 -0
  34. package/build/services/index.js.map +1 -1
  35. package/build/services/variable-group-compare.d.ts +80 -0
  36. package/build/services/variable-group-compare.d.ts.map +1 -0
  37. package/build/services/variable-group-compare.js +101 -0
  38. package/build/services/variable-group-compare.js.map +1 -0
  39. package/build/services/variable-group-service.d.ts +31 -0
  40. package/build/services/variable-group-service.d.ts.map +1 -1
  41. package/build/services/variable-group-service.js +110 -0
  42. package/build/services/variable-group-service.js.map +1 -1
  43. package/build/tools/build-tools.d.ts.map +1 -1
  44. package/build/tools/build-tools.js +17 -3
  45. package/build/tools/build-tools.js.map +1 -1
  46. package/build/tools/checklist-tools.d.ts.map +1 -1
  47. package/build/tools/checklist-tools.js +10 -8
  48. package/build/tools/checklist-tools.js.map +1 -1
  49. package/build/tools/configuration-tools.d.ts.map +1 -1
  50. package/build/tools/configuration-tools.js +3 -1
  51. package/build/tools/configuration-tools.js.map +1 -1
  52. package/build/tools/git-tools.d.ts +3 -0
  53. package/build/tools/git-tools.d.ts.map +1 -0
  54. package/build/tools/git-tools.js +37 -0
  55. package/build/tools/git-tools.js.map +1 -0
  56. package/build/tools/index.d.ts +1 -0
  57. package/build/tools/index.d.ts.map +1 -1
  58. package/build/tools/index.js +8 -3
  59. package/build/tools/index.js.map +1 -1
  60. package/build/tools/pull-request-tools.d.ts.map +1 -1
  61. package/build/tools/pull-request-tools.js +17 -13
  62. package/build/tools/pull-request-tools.js.map +1 -1
  63. package/build/tools/sync-tools.d.ts.map +1 -1
  64. package/build/tools/sync-tools.js +18 -8
  65. package/build/tools/sync-tools.js.map +1 -1
  66. package/build/tools/test-tools.d.ts.map +1 -1
  67. package/build/tools/test-tools.js +7 -7
  68. package/build/tools/test-tools.js.map +1 -1
  69. package/build/tools/variable-group-tools.d.ts.map +1 -1
  70. package/build/tools/variable-group-tools.js +45 -3
  71. package/build/tools/variable-group-tools.js.map +1 -1
  72. package/build/tools/visualize-tools.d.ts.map +1 -1
  73. package/build/tools/visualize-tools.js +5 -1
  74. package/build/tools/visualize-tools.js.map +1 -1
  75. package/build/tools/wiki-tools.d.ts.map +1 -1
  76. package/build/tools/wiki-tools.js +14 -12
  77. package/build/tools/wiki-tools.js.map +1 -1
  78. package/build/tools/work-item-tools.d.ts.map +1 -1
  79. package/build/tools/work-item-tools.js +11 -8
  80. package/build/tools/work-item-tools.js.map +1 -1
  81. package/build/types.d.ts +2 -0
  82. package/build/types.d.ts.map +1 -1
  83. package/package.json +2 -2
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Git Service - Azure DevOps repository branch operations
3
+ *
4
+ * Refs API notes (Microsoft Learn, api-version 7.1):
5
+ * - `filter` is a PREFIX match, and `ref.name` comes back as the FULL ref
6
+ * (`refs/heads/main`), never the short name.
7
+ * - A ref carries `objectId` (the commit SHA) and NO date. Ordering branches by
8
+ * time is therefore impossible from this endpoint alone.
9
+ * - `$top` caps at 1000; more results arrive via the `x-ms-continuationtoken`
10
+ * RESPONSE header, fed back as a `continuationToken` query param.
11
+ */
12
+ import type { AzureDevOpsClient } from '../azure-devops-client.js';
13
+ export interface GitRef {
14
+ name: string;
15
+ objectId: string;
16
+ isLocked?: boolean;
17
+ creator?: {
18
+ displayName?: string;
19
+ };
20
+ }
21
+ export interface Branch {
22
+ /** Short name, e.g. `main` (the `refs/heads/` prefix stripped). */
23
+ name: string;
24
+ /** Full ref name exactly as Azure DevOps returned it, e.g. `refs/heads/main`. */
25
+ fullName: string;
26
+ /** Commit SHA at the tip. The refs API exposes no commit date. */
27
+ objectId: string;
28
+ isLocked: boolean;
29
+ }
30
+ export interface ListBranchesResult {
31
+ project: string;
32
+ repositoryId: string;
33
+ filter: string;
34
+ branchCount: number;
35
+ /** True when more branches exist than `maxResults` allowed us to return. */
36
+ truncated: boolean;
37
+ branches: Branch[];
38
+ }
39
+ export interface LatestReleaseBranchResult {
40
+ project: string;
41
+ repositoryId: string;
42
+ prefix: string;
43
+ /** Null when no release branch carries a comparable version. */
44
+ branchName: string | null;
45
+ /** The portion after `prefix`, e.g. `35.0` for `release/35.0`. */
46
+ version: string | null;
47
+ objectId: string | null;
48
+ sortedBy: 'version (digit-aware natural sort, descending)';
49
+ candidateCount: number;
50
+ /** Versions considered, best first. Capped for readability. */
51
+ candidates: string[];
52
+ /**
53
+ * Branches under `prefix` with no digit in their name (`release/next`).
54
+ * Natural sort cannot rank these against `release/35.0`, and letting one win
55
+ * would be arbitrary, so they are excluded — but never silently.
56
+ */
57
+ ignoredNonVersionBranches: string[];
58
+ truncated: boolean;
59
+ }
60
+ /**
61
+ * Digit-aware descending comparison, so `release/10` beats `release/9`.
62
+ * A plain lexical sort gets this backwards.
63
+ */
64
+ export declare function compareVersionsDescending(a: string, b: string): number;
65
+ /** A version string is only rankable if it contains at least one digit. */
66
+ export declare function isVersionLike(version: string): boolean;
67
+ /**
68
+ * Pick the newest release branch by version name.
69
+ *
70
+ * Exported and pure so the ordering rules can be tested without a repository.
71
+ */
72
+ export declare function selectLatestRelease(branchNames: string[], prefix: string): {
73
+ branchName: string | null;
74
+ version: string | null;
75
+ candidates: string[];
76
+ ignored: string[];
77
+ };
78
+ export declare class GitService {
79
+ private readonly client;
80
+ constructor(client: AzureDevOpsClient);
81
+ /**
82
+ * Fetch refs, following `x-ms-continuationtoken` until `maxResults` is met.
83
+ *
84
+ * Returns `truncated: true` when the server still had a continuation token but
85
+ * we stopped. Never reports a partial list as complete.
86
+ */
87
+ private fetchRefs;
88
+ listBranches(project: string, repositoryId: string, options?: {
89
+ filter?: string;
90
+ maxResults?: number;
91
+ }): Promise<ListBranchesResult>;
92
+ getLatestReleaseBranch(project: string, repositoryId: string, options?: {
93
+ prefix?: string;
94
+ maxResults?: number;
95
+ }): Promise<LatestReleaseBranchResult>;
96
+ }
97
+ //# sourceMappingURL=git-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-service.d.ts","sourceRoot":"","sources":["../../src/services/git-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAQnE,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACpC;AAED,MAAM,WAAW,MAAM;IACrB,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,kEAAkE;IAClE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,gDAAgD,CAAC;IAC3D,cAAc,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB;;;;OAIG;IACH,yBAAyB,EAAE,MAAM,EAAE,CAAC;IACpC,SAAS,EAAE,OAAO,CAAC;CACpB;AASD;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EAAE,EACrB,MAAM,EAAE,MAAM,GACb;IAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAqBhG;AAED,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,iBAAiB;IAEtD;;;;;OAKG;YACW,SAAS;IA+BjB,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GACjD,OAAO,CAAC,kBAAkB,CAAC;IAuBxB,sBAAsB,CAC1B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GACjD,OAAO,CAAC,yBAAyB,CAAC;CAgCtC"}
@@ -0,0 +1,123 @@
1
+ /** Azure DevOps caps `$top` on the refs endpoint at 1000. */
2
+ const MAX_PAGE_SIZE = 1000;
3
+ const DEFAULT_RELEASE_PREFIX = 'release/';
4
+ /** `refs/heads/main` -> `main`. Leaves an already-short name alone. */
5
+ function shortBranchName(fullRefName) {
6
+ return fullRefName.startsWith('refs/heads/')
7
+ ? fullRefName.slice('refs/heads/'.length)
8
+ : fullRefName;
9
+ }
10
+ /**
11
+ * Digit-aware descending comparison, so `release/10` beats `release/9`.
12
+ * A plain lexical sort gets this backwards.
13
+ */
14
+ export function compareVersionsDescending(a, b) {
15
+ return b.localeCompare(a, undefined, { numeric: true, sensitivity: 'base' });
16
+ }
17
+ /** A version string is only rankable if it contains at least one digit. */
18
+ export function isVersionLike(version) {
19
+ return /\d/.test(version);
20
+ }
21
+ /**
22
+ * Pick the newest release branch by version name.
23
+ *
24
+ * Exported and pure so the ordering rules can be tested without a repository.
25
+ */
26
+ export function selectLatestRelease(branchNames, prefix) {
27
+ const ignored = [];
28
+ const candidates = [];
29
+ for (const name of branchNames) {
30
+ if (!name.startsWith(prefix))
31
+ continue;
32
+ const version = name.slice(prefix.length);
33
+ if (version.length === 0)
34
+ continue;
35
+ if (isVersionLike(version))
36
+ candidates.push(version);
37
+ else
38
+ ignored.push(name);
39
+ }
40
+ candidates.sort(compareVersionsDescending);
41
+ const version = candidates[0] ?? null;
42
+ return {
43
+ branchName: version === null ? null : `${prefix}${version}`,
44
+ version,
45
+ candidates,
46
+ ignored,
47
+ };
48
+ }
49
+ export class GitService {
50
+ client;
51
+ constructor(client) {
52
+ this.client = client;
53
+ }
54
+ /**
55
+ * Fetch refs, following `x-ms-continuationtoken` until `maxResults` is met.
56
+ *
57
+ * Returns `truncated: true` when the server still had a continuation token but
58
+ * we stopped. Never reports a partial list as complete.
59
+ */
60
+ async fetchRefs(project, repositoryId, filter, maxResults) {
61
+ const refs = [];
62
+ let continuationToken;
63
+ do {
64
+ const remaining = maxResults - refs.length;
65
+ const params = new URLSearchParams({
66
+ 'api-version': this.client.apiVersion,
67
+ filter,
68
+ $top: String(Math.min(MAX_PAGE_SIZE, remaining)),
69
+ });
70
+ if (continuationToken)
71
+ params.append('continuationToken', continuationToken);
72
+ const endpoint = `${encodeURIComponent(project)}/_apis/git/repositories/${encodeURIComponent(repositoryId)}/refs?${params.toString()}`;
73
+ const response = await this.client.requestRaw(endpoint, 'GET');
74
+ const body = response.data;
75
+ refs.push(...(body.value ?? []));
76
+ const header = response.headers?.['x-ms-continuationtoken'];
77
+ continuationToken = typeof header === 'string' && header.length > 0 ? header : undefined;
78
+ } while (continuationToken && refs.length < maxResults);
79
+ return { refs: refs.slice(0, maxResults), truncated: Boolean(continuationToken) };
80
+ }
81
+ async listBranches(project, repositoryId, options) {
82
+ this.client.validateProject(project);
83
+ const filter = options?.filter ?? 'heads/';
84
+ const maxResults = options?.maxResults ?? 200;
85
+ const { refs, truncated } = await this.fetchRefs(project, repositoryId, filter, maxResults);
86
+ return {
87
+ project,
88
+ repositoryId,
89
+ filter,
90
+ branchCount: refs.length,
91
+ truncated,
92
+ branches: refs.map((ref) => ({
93
+ name: shortBranchName(ref.name),
94
+ fullName: ref.name,
95
+ objectId: ref.objectId,
96
+ isLocked: ref.isLocked ?? false,
97
+ })),
98
+ };
99
+ }
100
+ async getLatestReleaseBranch(project, repositoryId, options) {
101
+ this.client.validateProject(project);
102
+ const prefix = options?.prefix ?? DEFAULT_RELEASE_PREFIX;
103
+ const maxResults = options?.maxResults ?? MAX_PAGE_SIZE;
104
+ const { refs, truncated } = await this.fetchRefs(project, repositoryId, `heads/${prefix}`, maxResults);
105
+ const branchNames = refs.map((ref) => shortBranchName(ref.name));
106
+ const { branchName, version, candidates, ignored } = selectLatestRelease(branchNames, prefix);
107
+ const winner = branchName === null ? undefined : refs.find((ref) => shortBranchName(ref.name) === branchName);
108
+ return {
109
+ project,
110
+ repositoryId,
111
+ prefix,
112
+ branchName,
113
+ version,
114
+ objectId: winner?.objectId ?? null,
115
+ sortedBy: 'version (digit-aware natural sort, descending)',
116
+ candidateCount: candidates.length,
117
+ candidates: candidates.slice(0, 10),
118
+ ignoredNonVersionBranches: ignored,
119
+ truncated,
120
+ };
121
+ }
122
+ }
123
+ //# sourceMappingURL=git-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-service.js","sourceRoot":"","sources":["../../src/services/git-service.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@ export { WikiService } from './wiki-service.js';
5
5
  export { WorkItemService } from './work-item-service.js';
6
6
  export { PullRequestService } from './pull-request-service.js';
7
7
  export { BuildService } from './build-service.js';
8
+ export { GitService } from './git-service.js';
8
9
  export { VariableGroupService } from './variable-group-service.js';
9
10
  export { SyncService } from './sync-service.js';
10
11
  export { ConfigurationService } from './configuration-service.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
@@ -5,6 +5,7 @@ export { WikiService } from './wiki-service.js';
5
5
  export { WorkItemService } from './work-item-service.js';
6
6
  export { PullRequestService } from './pull-request-service.js';
7
7
  export { BuildService } from './build-service.js';
8
+ export { GitService } from './git-service.js';
8
9
  export { VariableGroupService } from './variable-group-service.js';
9
10
  export { SyncService } from './sync-service.js';
10
11
  export { ConfigurationService } from './configuration-service.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Pure comparison/summary helpers for Azure DevOps variable groups.
3
+ *
4
+ * Kept free of any HTTP client so the secret-handling rules can be tested
5
+ * exhaustively without a live organisation.
6
+ *
7
+ * Secret rule (load-bearing): Azure DevOps returns a secret as
8
+ * `{ isSecret: true, value: null }` and OMITS `isSecret` entirely for a normal
9
+ * variable. We branch on `isSecret` and never read `.value` for a secret — so
10
+ * even if the API one day returned a real value, it could not reach the output.
11
+ */
12
+ export interface RawVariable {
13
+ value?: string | null;
14
+ isSecret?: boolean;
15
+ isReadOnly?: boolean;
16
+ }
17
+ export interface RawVariableGroup {
18
+ id: number;
19
+ name: string;
20
+ type?: string;
21
+ description?: string;
22
+ isShared?: boolean;
23
+ modifiedOn?: string;
24
+ variables?: Record<string, RawVariable>;
25
+ }
26
+ /**
27
+ * Suffixes recognised when grouping `<base>-<env>` variable groups.
28
+ *
29
+ * Callers may override these. The si source hardcoded exactly this list, so a
30
+ * team using `-prd` or `_dev` got an empty result forever, with no error.
31
+ */
32
+ export declare const DEFAULT_ENVIRONMENT_SUFFIXES: readonly ["-dev", "-development", "-qa", "-uat", "-staging", "-stage", "-test", "-prod", "-production"];
33
+ export declare function isSecret(variable: RawVariable): boolean;
34
+ export interface VariableSummary {
35
+ variableCount: number;
36
+ secretCount: number;
37
+ }
38
+ /** Count variables and secrets. Never touches a secret's value. */
39
+ export declare function summariseVariables(variables: Record<string, RawVariable> | undefined): VariableSummary;
40
+ export interface ValueDifference {
41
+ name: string;
42
+ valueInA: string | null | undefined;
43
+ valueInB: string | null | undefined;
44
+ }
45
+ export interface SecretPresenceDifference {
46
+ name: string;
47
+ isSecretInA: boolean;
48
+ isSecretInB: boolean;
49
+ }
50
+ export interface VariableGroupComparison {
51
+ groupA: {
52
+ id: number;
53
+ name: string;
54
+ };
55
+ groupB: {
56
+ id: number;
57
+ name: string;
58
+ };
59
+ onlyInA: string[];
60
+ onlyInB: string[];
61
+ inBothCount: number;
62
+ valueDifferences: ValueDifference[];
63
+ /** Names present in both where at least one side is a secret. Values never compared. */
64
+ secretsSkipped: string[];
65
+ /** A variable that is a secret on one side and plaintext on the other — a real drift finding. */
66
+ secretPresenceDifferences: SecretPresenceDifference[];
67
+ }
68
+ export declare function compareVariables(a: RawVariableGroup, b: RawVariableGroup): VariableGroupComparison;
69
+ export interface ParsedEnvironment {
70
+ baseName: string;
71
+ environment: string;
72
+ }
73
+ /**
74
+ * Split `billing-uat` into `{ baseName: 'billing', environment: 'uat' }`.
75
+ *
76
+ * Matches the LONGEST suffix so `-production` is not mistaken for `-prod`,
77
+ * and refuses a name that is nothing but a suffix.
78
+ */
79
+ export declare function parseEnvironment(groupName: string, suffixes: readonly string[]): ParsedEnvironment | null;
80
+ //# sourceMappingURL=variable-group-compare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variable-group-compare.d.ts","sourceRoot":"","sources":["../../src/services/variable-group-compare.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CACzC;AAED;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,yGAU/B,CAAC;AAEX,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAEvD;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,mEAAmE;AACnE,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,SAAS,GAAG,eAAe,CAMtG;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,wFAAwF;IACxF,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,iGAAiG;IACjG,yBAAyB,EAAE,wBAAwB,EAAE,CAAC;CACvD;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,gBAAgB,GAAG,uBAAuB,CA6ClG;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,iBAAiB,GAAG,IAAI,CAiB1B"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Pure comparison/summary helpers for Azure DevOps variable groups.
3
+ *
4
+ * Kept free of any HTTP client so the secret-handling rules can be tested
5
+ * exhaustively without a live organisation.
6
+ *
7
+ * Secret rule (load-bearing): Azure DevOps returns a secret as
8
+ * `{ isSecret: true, value: null }` and OMITS `isSecret` entirely for a normal
9
+ * variable. We branch on `isSecret` and never read `.value` for a secret — so
10
+ * even if the API one day returned a real value, it could not reach the output.
11
+ */
12
+ /**
13
+ * Suffixes recognised when grouping `<base>-<env>` variable groups.
14
+ *
15
+ * Callers may override these. The si source hardcoded exactly this list, so a
16
+ * team using `-prd` or `_dev` got an empty result forever, with no error.
17
+ */
18
+ export const DEFAULT_ENVIRONMENT_SUFFIXES = [
19
+ '-dev',
20
+ '-development',
21
+ '-qa',
22
+ '-uat',
23
+ '-staging',
24
+ '-stage',
25
+ '-test',
26
+ '-prod',
27
+ '-production',
28
+ ];
29
+ export function isSecret(variable) {
30
+ return variable.isSecret === true;
31
+ }
32
+ /** Count variables and secrets. Never touches a secret's value. */
33
+ export function summariseVariables(variables) {
34
+ const entries = Object.values(variables ?? {});
35
+ return {
36
+ variableCount: entries.length,
37
+ secretCount: entries.filter(isSecret).length,
38
+ };
39
+ }
40
+ export function compareVariables(a, b) {
41
+ const varsA = a.variables ?? {};
42
+ const varsB = b.variables ?? {};
43
+ const namesA = Object.keys(varsA);
44
+ const namesB = Object.keys(varsB);
45
+ const onlyInA = namesA.filter((name) => !(name in varsB)).sort();
46
+ const onlyInB = namesB.filter((name) => !(name in varsA)).sort();
47
+ const inBoth = namesA.filter((name) => name in varsB).sort();
48
+ const valueDifferences = [];
49
+ const secretsSkipped = [];
50
+ const secretPresenceDifferences = [];
51
+ for (const name of inBoth) {
52
+ const varA = varsA[name];
53
+ const varB = varsB[name];
54
+ const secretA = isSecret(varA);
55
+ const secretB = isSecret(varB);
56
+ if (secretA !== secretB) {
57
+ secretPresenceDifferences.push({ name, isSecretInA: secretA, isSecretInB: secretB });
58
+ }
59
+ // Either side secret => never read either value.
60
+ if (secretA || secretB) {
61
+ secretsSkipped.push(name);
62
+ continue;
63
+ }
64
+ if (varA.value !== varB.value) {
65
+ valueDifferences.push({ name, valueInA: varA.value, valueInB: varB.value });
66
+ }
67
+ }
68
+ return {
69
+ groupA: { id: a.id, name: a.name },
70
+ groupB: { id: b.id, name: b.name },
71
+ onlyInA,
72
+ onlyInB,
73
+ inBothCount: inBoth.length,
74
+ valueDifferences,
75
+ secretsSkipped,
76
+ secretPresenceDifferences,
77
+ };
78
+ }
79
+ /**
80
+ * Split `billing-uat` into `{ baseName: 'billing', environment: 'uat' }`.
81
+ *
82
+ * Matches the LONGEST suffix so `-production` is not mistaken for `-prod`,
83
+ * and refuses a name that is nothing but a suffix.
84
+ */
85
+ export function parseEnvironment(groupName, suffixes) {
86
+ const lower = groupName.toLowerCase();
87
+ const matches = suffixes
88
+ .filter((suffix) => lower.endsWith(suffix.toLowerCase()))
89
+ .sort((x, y) => y.length - x.length);
90
+ for (const suffix of matches) {
91
+ const baseName = groupName.slice(0, groupName.length - suffix.length);
92
+ if (baseName.length === 0)
93
+ continue;
94
+ return {
95
+ baseName,
96
+ environment: suffix.replace(/^[-_]/, '').toLowerCase(),
97
+ };
98
+ }
99
+ return null;
100
+ }
101
+ //# sourceMappingURL=variable-group-compare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variable-group-compare.js","sourceRoot":"","sources":["../../src/services/variable-group-compare.ts"],"names":[],"mappings":"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"}
@@ -2,10 +2,41 @@
2
2
  * Variable Group Service - Azure DevOps variable group operations
3
3
  */
4
4
  import type { AzureDevOpsClient } from '../azure-devops-client.js';
5
+ import { type VariableGroupComparison } from './variable-group-compare.js';
5
6
  export declare class VariableGroupService {
6
7
  private readonly client;
7
8
  constructor(client: AzureDevOpsClient);
9
+ /**
10
+ * Fetch a group exactly as Azure DevOps returned it.
11
+ *
12
+ * `getVariableGroup` below masks every secret to the literal '***SECRET***'.
13
+ * Comparing masked values would make any two secrets look identical, so the
14
+ * comparison tools read the raw payload and branch on `isSecret` instead.
15
+ */
16
+ private fetchRawGroup;
17
+ private fetchRawGroups;
8
18
  getVariableGroups(project: string): Promise<any>;
9
19
  getVariableGroup(project: string, groupId: number): Promise<any>;
20
+ /** Side-by-side diff of two variable groups. Secret values are never read or emitted. */
21
+ compareVariableGroups(project: string, groupIdA: number, groupIdB: number): Promise<VariableGroupComparison & {
22
+ project: string;
23
+ }>;
24
+ /**
25
+ * Detect `<base>-<env>` variable-group families and diff each environment
26
+ * against the first one in the family.
27
+ *
28
+ * Reports what it could NOT classify (`unmatchedGroups`) and families with a
29
+ * single environment (`incompleteSets`), so an empty result is explainable
30
+ * rather than looking like "nothing has drifted".
31
+ */
32
+ compareEnvironments(project: string, options?: {
33
+ nameContains?: string;
34
+ environmentSuffixes?: string[];
35
+ }): Promise<any>;
36
+ /** Overview of variable groups with variable/secret counts. Secret values are never read. */
37
+ getVariableGroupSummaries(project: string, options?: {
38
+ nameContains?: string;
39
+ maxResults?: number;
40
+ }): Promise<any>;
10
41
  }
11
42
  //# sourceMappingURL=variable-group-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"variable-group-service.d.ts","sourceRoot":"","sources":["../../src/services/variable-group-service.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAGnE,qBAAa,oBAAoB;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,iBAAiB;IAEhD,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAkChD,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;CA8BvE"}
1
+ {"version":3,"file":"variable-group-service.d.ts","sourceRoot":"","sources":["../../src/services/variable-group-service.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,OAAO,EAML,KAAK,uBAAuB,EAC7B,MAAM,6BAA6B,CAAC;AAErC,qBAAa,oBAAoB;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,iBAAiB;IAEtD;;;;;;OAMG;YACW,aAAa;YAMb,cAAc;IAOtB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAkChD,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IA+BtE,yFAAyF;IACnF,qBAAqB,CACzB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,uBAAuB,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAWzD;;;;;;;OAOG;IACG,mBAAmB,CACvB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAClE,OAAO,CAAC,GAAG,CAAC;IA+Df,6FAA6F;IACvF,yBAAyB,CAC7B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GACvD,OAAO,CAAC,GAAG,CAAC;CAiChB"}
@@ -1,8 +1,23 @@
1
+ import { compareVariables, parseEnvironment, summariseVariables, DEFAULT_ENVIRONMENT_SUFFIXES, } from './variable-group-compare.js';
1
2
  export class VariableGroupService {
2
3
  client;
3
4
  constructor(client) {
4
5
  this.client = client;
5
6
  }
7
+ /**
8
+ * Fetch a group exactly as Azure DevOps returned it.
9
+ *
10
+ * `getVariableGroup` below masks every secret to the literal '***SECRET***'.
11
+ * Comparing masked values would make any two secrets look identical, so the
12
+ * comparison tools read the raw payload and branch on `isSecret` instead.
13
+ */
14
+ async fetchRawGroup(project, groupId) {
15
+ return this.client.get(`${project}/_apis/distributedtask/variablegroups/${groupId}?api-version=${this.client.apiVersion}`);
16
+ }
17
+ async fetchRawGroups(project) {
18
+ const response = await this.client.get(`${project}/_apis/distributedtask/variablegroups?api-version=${this.client.apiVersion}`);
19
+ return response.value ?? [];
20
+ }
6
21
  async getVariableGroups(project) {
7
22
  this.client.validateProject(project);
8
23
  const response = await this.client.get(`${project}/_apis/distributedtask/variablegroups?api-version=${this.client.apiVersion}`);
@@ -58,5 +73,100 @@ export class VariableGroupService {
58
73
  }, {})
59
74
  };
60
75
  }
76
+ /** Side-by-side diff of two variable groups. Secret values are never read or emitted. */
77
+ async compareVariableGroups(project, groupIdA, groupIdB) {
78
+ this.client.validateProject(project);
79
+ const [groupA, groupB] = await Promise.all([
80
+ this.fetchRawGroup(project, groupIdA),
81
+ this.fetchRawGroup(project, groupIdB),
82
+ ]);
83
+ return { project, ...compareVariables(groupA, groupB) };
84
+ }
85
+ /**
86
+ * Detect `<base>-<env>` variable-group families and diff each environment
87
+ * against the first one in the family.
88
+ *
89
+ * Reports what it could NOT classify (`unmatchedGroups`) and families with a
90
+ * single environment (`incompleteSets`), so an empty result is explainable
91
+ * rather than looking like "nothing has drifted".
92
+ */
93
+ async compareEnvironments(project, options) {
94
+ this.client.validateProject(project);
95
+ const suffixes = options?.environmentSuffixes?.length
96
+ ? options.environmentSuffixes
97
+ : [...DEFAULT_ENVIRONMENT_SUFFIXES];
98
+ const needle = options?.nameContains?.toLowerCase();
99
+ const groups = (await this.fetchRawGroups(project)).filter((group) => !needle || group.name.toLowerCase().includes(needle));
100
+ const families = new Map();
101
+ const unmatchedGroups = [];
102
+ for (const group of groups) {
103
+ const parsed = parseEnvironment(group.name, suffixes);
104
+ if (!parsed) {
105
+ unmatchedGroups.push(group.name);
106
+ continue;
107
+ }
108
+ const key = parsed.baseName.toLowerCase();
109
+ const family = families.get(key) ?? [];
110
+ family.push({ environment: parsed.environment, group });
111
+ families.set(key, family);
112
+ }
113
+ const environmentSets = [];
114
+ const incompleteSets = [];
115
+ for (const [baseName, members] of families) {
116
+ members.sort((x, y) => x.environment.localeCompare(y.environment));
117
+ const environments = members.map((m) => ({
118
+ environment: m.environment,
119
+ group: { id: m.group.id, name: m.group.name },
120
+ }));
121
+ if (members.length < 2) {
122
+ incompleteSets.push({ baseName, environments });
123
+ continue;
124
+ }
125
+ // Diff every environment against the first, so N environments yield N-1
126
+ // comparisons anchored on a single baseline.
127
+ const baseline = members[0];
128
+ const comparisons = members
129
+ .slice(1)
130
+ .map((member) => compareVariables(baseline.group, member.group));
131
+ environmentSets.push({ baseName, environments, comparisons });
132
+ }
133
+ return {
134
+ project,
135
+ environmentSuffixes: suffixes,
136
+ groupsScanned: groups.length,
137
+ environmentSetCount: environmentSets.length,
138
+ environmentSets,
139
+ incompleteSets,
140
+ unmatchedGroups,
141
+ };
142
+ }
143
+ /** Overview of variable groups with variable/secret counts. Secret values are never read. */
144
+ async getVariableGroupSummaries(project, options) {
145
+ this.client.validateProject(project);
146
+ const maxResults = options?.maxResults ?? 100;
147
+ const needle = options?.nameContains?.toLowerCase();
148
+ const matched = (await this.fetchRawGroups(project)).filter((group) => !needle || group.name.toLowerCase().includes(needle));
149
+ const returned = matched.slice(0, maxResults);
150
+ const summaries = returned.map((group) => ({
151
+ id: group.id,
152
+ name: group.name,
153
+ type: group.type,
154
+ description: group.description,
155
+ isShared: group.isShared ?? false,
156
+ modifiedOn: group.modifiedOn,
157
+ ...summariseVariables(group.variables),
158
+ }));
159
+ return {
160
+ project,
161
+ groupCount: summaries.length,
162
+ truncated: matched.length > returned.length,
163
+ // Totals describe exactly the groups returned, never a wider population.
164
+ totals: {
165
+ variableCount: summaries.reduce((sum, group) => sum + group.variableCount, 0),
166
+ secretCount: summaries.reduce((sum, group) => sum + group.secretCount, 0),
167
+ },
168
+ variableGroups: summaries,
169
+ };
170
+ }
61
171
  }
62
172
  //# sourceMappingURL=variable-group-service.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"variable-group-service.js","sourceRoot":"","sources":["../../src/services/variable-group-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"variable-group-service.js","sourceRoot":"","sources":["../../src/services/variable-group-service.ts"],"names":[],"mappings":"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"}