@elisra-devops/docgen-data-provider 1.22.0 → 1.24.0

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 (49) hide show
  1. package/bin/helpers/helper.js.map +1 -1
  2. package/bin/helpers/test/tfs.test.d.ts +1 -0
  3. package/bin/helpers/test/tfs.test.js +613 -0
  4. package/bin/helpers/test/tfs.test.js.map +1 -0
  5. package/bin/helpers/tfs.js +1 -1
  6. package/bin/helpers/tfs.js.map +1 -1
  7. package/bin/modules/GitDataProvider.js.map +1 -1
  8. package/bin/modules/PipelinesDataProvider.js +3 -2
  9. package/bin/modules/PipelinesDataProvider.js.map +1 -1
  10. package/bin/modules/ResultDataProvider.d.ts +200 -17
  11. package/bin/modules/ResultDataProvider.js +628 -195
  12. package/bin/modules/ResultDataProvider.js.map +1 -1
  13. package/bin/modules/TestDataProvider.js +7 -7
  14. package/bin/modules/TestDataProvider.js.map +1 -1
  15. package/bin/modules/TicketsDataProvider.d.ts +1 -1
  16. package/bin/modules/TicketsDataProvider.js +3 -2
  17. package/bin/modules/TicketsDataProvider.js.map +1 -1
  18. package/bin/modules/test/JfrogDataProvider.test.d.ts +1 -0
  19. package/bin/modules/test/JfrogDataProvider.test.js +110 -0
  20. package/bin/modules/test/JfrogDataProvider.test.js.map +1 -0
  21. package/bin/modules/test/ResultDataProvider.test.d.ts +1 -0
  22. package/bin/modules/test/ResultDataProvider.test.js +478 -0
  23. package/bin/modules/test/ResultDataProvider.test.js.map +1 -0
  24. package/bin/modules/test/gitDataProvider.test.js +424 -120
  25. package/bin/modules/test/gitDataProvider.test.js.map +1 -1
  26. package/bin/modules/test/managmentDataProvider.test.js +283 -28
  27. package/bin/modules/test/managmentDataProvider.test.js.map +1 -1
  28. package/bin/modules/test/pipelineDataProvider.test.js +229 -45
  29. package/bin/modules/test/pipelineDataProvider.test.js.map +1 -1
  30. package/bin/modules/test/testDataProvider.test.js +225 -81
  31. package/bin/modules/test/testDataProvider.test.js.map +1 -1
  32. package/bin/modules/test/ticketsDataProvider.test.js +310 -82
  33. package/bin/modules/test/ticketsDataProvider.test.js.map +1 -1
  34. package/package.json +1 -1
  35. package/src/helpers/helper.ts +16 -14
  36. package/src/helpers/test/tfs.test.ts +748 -0
  37. package/src/helpers/tfs.ts +1 -1
  38. package/src/modules/GitDataProvider.ts +10 -10
  39. package/src/modules/PipelinesDataProvider.ts +2 -2
  40. package/src/modules/ResultDataProvider.ts +834 -260
  41. package/src/modules/TestDataProvider.ts +8 -8
  42. package/src/modules/TicketsDataProvider.ts +5 -9
  43. package/src/modules/test/JfrogDataProvider.test.ts +171 -0
  44. package/src/modules/test/ResultDataProvider.test.ts +581 -0
  45. package/src/modules/test/gitDataProvider.test.ts +671 -187
  46. package/src/modules/test/managmentDataProvider.test.ts +386 -26
  47. package/src/modules/test/pipelineDataProvider.test.ts +281 -52
  48. package/src/modules/test/testDataProvider.test.ts +307 -105
  49. package/src/modules/test/ticketsDataProvider.test.ts +425 -129
@@ -1,207 +1,691 @@
1
- import DgDataProviderAzureDevOps from "../..";
1
+ import axios from 'axios';
2
+ import { TFSServices } from '../../helpers/tfs';
3
+ import GitDataProvider from '../GitDataProvider';
4
+ import logger from '../../utils/logger';
2
5
 
3
- require("dotenv").config();
4
- jest.setTimeout(60000);
5
- const orgUrl = process.env.ORG_URL;
6
- const token = process.env.PAT;
6
+ jest.mock('../../helpers/tfs');
7
+ jest.mock('../../utils/logger');
7
8
 
8
- const dgDataProviderAzureDevOps = new DgDataProviderAzureDevOps(orgUrl,token);
9
+ describe('GitDataProvider - GetCommitForPipeline', () => {
10
+ let gitDataProvider: GitDataProvider;
11
+ const mockOrgUrl = 'https://dev.azure.com/orgname/';
12
+ const mockToken = 'mock-token';
13
+ const mockProjectId = 'project-123';
14
+ const mockBuildId = 456;
9
15
 
16
+ beforeEach(() => {
17
+ jest.clearAllMocks();
18
+ gitDataProvider = new GitDataProvider(mockOrgUrl, mockToken);
19
+ });
20
+
21
+ it('should return the sourceVersion from build information', async () => {
22
+ // Arrange
23
+ const mockCommitSha = 'abc123def456';
24
+ const mockResponse = {
25
+ id: mockBuildId,
26
+ sourceVersion: mockCommitSha,
27
+ status: 'completed'
28
+ };
29
+
30
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockResponse);
31
+
32
+ // Act
33
+ const result = await gitDataProvider.GetCommitForPipeline(mockProjectId, mockBuildId);
34
+
35
+ // Assert
36
+ expect(TFSServices.getItemContent).toHaveBeenCalledWith(
37
+ `${mockOrgUrl}${mockProjectId}/_apis/build/builds/${mockBuildId}`,
38
+ mockToken,
39
+ 'get'
40
+ );
41
+ expect(result).toBe(mockCommitSha);
42
+ });
43
+
44
+ it('should throw an error if the API call fails', async () => {
45
+ // Arrange
46
+ const expectedError = new Error('API call failed');
47
+ (TFSServices.getItemContent as jest.Mock).mockRejectedValueOnce(expectedError);
48
+
49
+ // Act & Assert
50
+ await expect(gitDataProvider.GetCommitForPipeline(mockProjectId, mockBuildId))
51
+ .rejects.toThrow('API call failed');
52
+
53
+ expect(TFSServices.getItemContent).toHaveBeenCalledWith(
54
+ `${mockOrgUrl}${mockProjectId}/_apis/build/builds/${mockBuildId}`,
55
+ mockToken,
56
+ 'get'
57
+ );
58
+ });
59
+
60
+ it('should return undefined if the response does not contain sourceVersion', async () => {
61
+ // Arrange
62
+ const mockResponse = {
63
+ id: mockBuildId,
64
+ status: 'completed'
65
+ // No sourceVersion property
66
+ };
67
+
68
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockResponse);
69
+
70
+ // Act
71
+ const result = await gitDataProvider.GetCommitForPipeline(mockProjectId, mockBuildId);
72
+
73
+ // Assert
74
+ expect(TFSServices.getItemContent).toHaveBeenCalledWith(
75
+ `${mockOrgUrl}${mockProjectId}/_apis/build/builds/${mockBuildId}`,
76
+ mockToken,
77
+ 'get'
78
+ );
79
+ expect(result).toBeUndefined();
80
+ });
81
+
82
+ it('should correctly construct URL with given project ID and build ID', async () => {
83
+ // Arrange
84
+ const customProjectId = 'custom-project';
85
+ const customBuildId = 789;
86
+ const mockCommitSha = 'xyz789abc';
87
+ const mockResponse = { sourceVersion: mockCommitSha };
88
+
89
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockResponse);
90
+
91
+ // Act
92
+ await gitDataProvider.GetCommitForPipeline(customProjectId, customBuildId);
93
+
94
+ // Assert
95
+ expect(TFSServices.getItemContent).toHaveBeenCalledWith(
96
+ `${mockOrgUrl}${customProjectId}/_apis/build/builds/${customBuildId}`,
97
+ mockToken,
98
+ 'get'
99
+ );
100
+ });
101
+
102
+ it('should handle different organization URLs correctly', async () => {
103
+ // Arrange
104
+ const altOrgUrl = 'https://dev.azure.com/different-org/';
105
+ const altGitDataProvider = new GitDataProvider(altOrgUrl, mockToken);
106
+ const mockResponse = { sourceVersion: 'commit-sha' };
107
+
108
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockResponse);
109
+
110
+ // Act
111
+ await altGitDataProvider.GetCommitForPipeline(mockProjectId, mockBuildId);
112
+
113
+ // Assert
114
+ expect(TFSServices.getItemContent).toHaveBeenCalledWith(
115
+ `${altOrgUrl}${mockProjectId}/_apis/build/builds/${mockBuildId}`,
116
+ mockToken,
117
+ 'get'
118
+ );
119
+ });
120
+ });
121
+ describe('GitDataProvider - GetTeamProjectGitReposList', () => {
122
+ let gitDataProvider: GitDataProvider;
123
+ const mockOrgUrl = 'https://dev.azure.com/orgname/';
124
+ const mockToken = 'mock-token';
125
+ const mockTeamProject = 'project-123';
126
+
127
+ beforeEach(() => {
128
+ jest.clearAllMocks();
129
+ gitDataProvider = new GitDataProvider(mockOrgUrl, mockToken);
130
+ });
131
+
132
+ it('should return sorted repositories when API call succeeds', async () => {
133
+ // Arrange
134
+ const mockRepos = {
135
+ value: [
136
+ { id: 'repo2', name: 'ZRepo' },
137
+ { id: 'repo1', name: 'ARepo' },
138
+ { id: 'repo3', name: 'MRepo' }
139
+ ]
140
+ };
141
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockRepos);
142
+
143
+ // Act
144
+ const result = await gitDataProvider.GetTeamProjectGitReposList(mockTeamProject);
145
+
146
+ // Assert
147
+ expect(TFSServices.getItemContent).toHaveBeenCalledWith(
148
+ `${mockOrgUrl}/${mockTeamProject}/_apis/git/repositories`,
149
+ mockToken,
150
+ 'get'
151
+ );
152
+ expect(result).toHaveLength(3);
153
+ expect(result[0].name).toBe('ARepo');
154
+ expect(result[1].name).toBe('MRepo');
155
+ expect(result[2].name).toBe('ZRepo');
156
+ expect(logger.debug).toHaveBeenCalledWith(
157
+ expect.stringContaining(`fetching repos list for team project - ${mockTeamProject}`)
158
+ );
159
+ });
10
160
 
11
- describe("git module - tests", () => {
12
- test("should return repo list for teamProject", async () => {
13
- let gitDataProvider = await dgDataProviderAzureDevOps.getGitDataProvider();
14
- let json: any = await gitDataProvider.GetTeamProjectGitReposList(
15
- "tests"
161
+ it('should return empty array when no repositories exist', async () => {
162
+ // Arrange
163
+ const mockEmptyRepos = { value: [] };
164
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockEmptyRepos);
165
+
166
+ // Act
167
+ const result = await gitDataProvider.GetTeamProjectGitReposList(mockTeamProject);
168
+
169
+ // Assert
170
+ expect(result).toEqual([]);
171
+ });
172
+
173
+ it('should handle API errors appropriately', async () => {
174
+ // Arrange
175
+ const mockError = new Error('API Error');
176
+ (TFSServices.getItemContent as jest.Mock).mockRejectedValueOnce(mockError);
177
+
178
+ // Act & Assert
179
+ await expect(gitDataProvider.GetTeamProjectGitReposList(mockTeamProject))
180
+ .rejects.toThrow('API Error');
181
+ });
182
+ });
183
+
184
+ describe('GitDataProvider - GetFileFromGitRepo', () => {
185
+ let gitDataProvider: GitDataProvider;
186
+ const mockOrgUrl = 'https://dev.azure.com/orgname/';
187
+ const mockToken = 'mock-token';
188
+ const mockProjectName = 'project-123';
189
+ const mockRepoId = 'repo-456';
190
+ const mockFileName = 'README.md';
191
+ const mockVersion = { version: 'main', versionType: 'branch' };
192
+
193
+ beforeEach(() => {
194
+ jest.clearAllMocks();
195
+ gitDataProvider = new GitDataProvider(mockOrgUrl, mockToken);
196
+ });
197
+
198
+ it('should return file content when file exists', async () => {
199
+ // Arrange
200
+ const mockContent = 'This is a test readme file';
201
+ const mockResponse = { content: mockContent };
202
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockResponse);
203
+
204
+ // Act
205
+ const result = await gitDataProvider.GetFileFromGitRepo(
206
+ mockProjectName,
207
+ mockRepoId,
208
+ mockFileName,
209
+ mockVersion
210
+ );
211
+
212
+ // Assert
213
+ expect(TFSServices.getItemContent).toHaveBeenCalledWith(
214
+ expect.stringContaining(`${mockOrgUrl}${mockProjectName}/_apis/git/repositories/${mockRepoId}/items`),
215
+ mockToken,
216
+ 'get',
217
+ {},
218
+ {},
219
+ false
220
+ );
221
+ expect(result).toBe(mockContent);
222
+ });
223
+
224
+ it('should handle special characters in version by encoding them', async () => {
225
+ // Arrange
226
+ const specialVersion = { version: 'feature/branch#123', versionType: 'branch' };
227
+ const mockResponse = { content: 'content' };
228
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockResponse);
229
+
230
+ // Act
231
+ await gitDataProvider.GetFileFromGitRepo(
232
+ mockProjectName,
233
+ mockRepoId,
234
+ mockFileName,
235
+ specialVersion
236
+ );
237
+
238
+ // Assert
239
+ expect(TFSServices.getItemContent).toHaveBeenCalledWith(
240
+ expect.stringContaining('versionDescriptor.version=feature%2Fbranch%23123'),
241
+ expect.anything(),
242
+ expect.anything(),
243
+ expect.anything(),
244
+ expect.anything(),
245
+ expect.anything()
246
+ );
247
+ });
248
+
249
+ it('should use custom gitRepoUrl if provided', async () => {
250
+ // Arrange
251
+ const mockCustomUrl = 'https://custom.git.url';
252
+ const mockResponse = { content: 'content' };
253
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockResponse);
254
+
255
+ // Act
256
+ await gitDataProvider.GetFileFromGitRepo(
257
+ mockProjectName,
258
+ mockRepoId,
259
+ mockFileName,
260
+ mockVersion,
261
+ mockCustomUrl
262
+ );
263
+
264
+ // Assert
265
+ expect(TFSServices.getItemContent).toHaveBeenCalledWith(
266
+ expect.stringContaining(mockCustomUrl),
267
+ expect.anything(),
268
+ expect.anything(),
269
+ expect.anything(),
270
+ expect.anything(),
271
+ expect.anything()
16
272
  );
17
- expect(json).toBeDefined();
18
273
  });
19
- test("should return repo from repoid", async () => {
20
- let gitDataProvider = await dgDataProviderAzureDevOps.getGitDataProvider();
21
- let json: any = await gitDataProvider.GetGitRepoFromRepoId(
22
- "68f2aee7-0864-458e-93ce-320303a080ed"
274
+
275
+ it('should return undefined when file does not exist', async () => {
276
+ // Arrange
277
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce({});
278
+
279
+ // Act
280
+ const result = await gitDataProvider.GetFileFromGitRepo(
281
+ mockProjectName,
282
+ mockRepoId,
283
+ mockFileName,
284
+ mockVersion
285
+ );
286
+
287
+ // Assert
288
+ expect(result).toBeUndefined();
289
+ });
290
+
291
+ it('should log warning and return undefined when error occurs', async () => {
292
+ // Arrange
293
+ const mockError = new Error('File not found');
294
+ (TFSServices.getItemContent as jest.Mock).mockRejectedValueOnce(mockError);
295
+
296
+ // Act
297
+ const result = await gitDataProvider.GetFileFromGitRepo(
298
+ mockProjectName,
299
+ mockRepoId,
300
+ mockFileName,
301
+ mockVersion
302
+ );
303
+
304
+ // Assert
305
+ expect(logger.warn).toHaveBeenCalledWith(
306
+ expect.stringContaining(`File ${mockFileName} could not be read: ${mockError.message}`)
307
+ );
308
+ expect(result).toBeUndefined();
309
+ });
310
+ });
311
+
312
+ describe('GitDataProvider - CheckIfItemExist', () => {
313
+ let gitDataProvider: GitDataProvider;
314
+ const mockOrgUrl = 'https://dev.azure.com/orgname/';
315
+ const mockToken = 'mock-token';
316
+ const mockGitApiUrl = 'https://dev.azure.com/orgname/project/_apis/git/repositories/repo-id';
317
+ const mockItemPath = 'path/to/file.txt';
318
+ const mockVersion = { version: 'main', versionType: 'branch' };
319
+
320
+ beforeEach(() => {
321
+ jest.clearAllMocks();
322
+ gitDataProvider = new GitDataProvider(mockOrgUrl, mockToken);
323
+ });
324
+
325
+ it('should return true when item exists', async () => {
326
+ // Arrange
327
+ const mockResponse = { path: mockItemPath, content: 'content' };
328
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockResponse);
329
+
330
+ // Act
331
+ const result = await gitDataProvider.CheckIfItemExist(
332
+ mockGitApiUrl,
333
+ mockItemPath,
334
+ mockVersion
335
+ );
336
+
337
+ // Assert
338
+ expect(TFSServices.getItemContent).toHaveBeenCalledWith(
339
+ expect.stringContaining(`${mockGitApiUrl}/items?path=${mockItemPath}`),
340
+ mockToken,
341
+ 'get',
342
+ {},
343
+ {},
344
+ false
23
345
  );
24
- expect(json).toBeDefined();
346
+ expect(result).toBe(true);
25
347
  });
26
- test("should return repo by pullrequest id", async () => {
27
- let gitDataProvider = await dgDataProviderAzureDevOps.getGitDataProvider();
28
- let json: any = await gitDataProvider.GetGitRepoFromPrId(
29
- 73
348
+
349
+ it('should return false when item does not exist', async () => {
350
+ // Arrange
351
+ (TFSServices.getItemContent as jest.Mock).mockRejectedValueOnce(new Error('Not found'));
352
+
353
+ // Act
354
+ const result = await gitDataProvider.CheckIfItemExist(
355
+ mockGitApiUrl,
356
+ mockItemPath,
357
+ mockVersion
30
358
  );
31
- expect(json.repository).toBeDefined();
359
+
360
+ // Assert
361
+ expect(result).toBe(false);
32
362
  });
33
- test("should return commits by pullrequest & repo id", async () => {
34
- let gitDataProvider = await dgDataProviderAzureDevOps.getGitDataProvider();
35
- let json: any = await gitDataProvider.GetGitRepoFromPrId(73);
36
- let commitJson: any = await gitDataProvider.GetPullRequestCommits(
37
- json.repository.id,
38
- 73
363
+
364
+ it('should return false when API returns null', async () => {
365
+ // Arrange
366
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(null);
367
+
368
+ // Act
369
+ const result = await gitDataProvider.CheckIfItemExist(
370
+ mockGitApiUrl,
371
+ mockItemPath,
372
+ mockVersion
39
373
  );
40
- expect(commitJson.value.length).toBeGreaterThan(0);
374
+
375
+ // Assert
376
+ expect(result).toBe(false);
41
377
  });
42
- test("should return pullrequest threads", async () => {
43
- let gitDataProvider = await dgDataProviderAzureDevOps.getGitDataProvider();
44
- let json = await gitDataProvider.GetPullRequestComments(
45
- "tests",
46
- "68f2aee7-0864-458e-93ce-320303a080ed",
47
- 73
378
+
379
+ it('should handle special characters in version', async () => {
380
+ // Arrange
381
+ const specialVersion = { version: 'feature/branch#123', versionType: 'branch' };
382
+ const mockResponse = { path: mockItemPath };
383
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockResponse);
384
+
385
+ // Act
386
+ await gitDataProvider.CheckIfItemExist(
387
+ mockGitApiUrl,
388
+ mockItemPath,
389
+ specialVersion
48
390
  );
49
- expect(json.count).toBeDefined;
391
+
392
+ // Assert
393
+ expect(TFSServices.getItemContent).toHaveBeenCalledWith(
394
+ expect.stringContaining('versionDescriptor.version=feature%2Fbranch%23123'),
395
+ expect.anything(),
396
+ expect.anything(),
397
+ expect.anything(),
398
+ expect.anything(),
399
+ expect.anything()
400
+ );
401
+ });
402
+ });
403
+
404
+ describe('GitDataProvider - GetPullRequestsInCommitRangeWithoutLinkedItems', () => {
405
+ let gitDataProvider: GitDataProvider;
406
+ const mockOrgUrl = 'https://dev.azure.com/orgname/';
407
+ const mockToken = 'mock-token';
408
+ const mockProjectId = 'project-123';
409
+ const mockRepoId = 'repo-456';
410
+
411
+ beforeEach(() => {
412
+ jest.clearAllMocks();
413
+ gitDataProvider = new GitDataProvider(mockOrgUrl, mockToken);
50
414
  });
51
- test("should create pullrequest thread", async () => {
52
- let data = {
53
- comments: [
415
+
416
+ it('should return filtered pull requests matching commit ids', async () => {
417
+ // Arrange
418
+ const mockCommits = {
419
+ value: [
420
+ { commitId: 'commit-1' },
421
+ { commitId: 'commit-2' }
422
+ ]
423
+ };
424
+
425
+ const mockPullRequests = {
426
+ count: 3,
427
+ value: [
54
428
  {
55
- parentCommentId: 0,
56
- content: "Should we add a comment about what this value means?",
57
- commentType: 1,
58
- },
59
- ],
60
- status: 1,
61
- threadContext: {
62
- filePath: "/assaf.txt",
63
- leftFileEnd: null,
64
- leftFileStart: null,
65
- rightFileEnd: {
66
- line: 2,
67
- offset: 1,
429
+ pullRequestId: 101,
430
+ title: 'PR 1',
431
+ createdBy: { displayName: 'User 1' },
432
+ creationDate: '2023-01-01',
433
+ closedDate: '2023-01-02',
434
+ description: 'Description 1',
435
+ lastMergeCommit: { commitId: 'commit-1' }
68
436
  },
69
- rightFileStart: {
70
- line: 2,
71
- offset: 5,
437
+ {
438
+ pullRequestId: 102,
439
+ title: 'PR 2',
440
+ createdBy: { displayName: 'User 2' },
441
+ creationDate: '2023-02-01',
442
+ closedDate: '2023-02-02',
443
+ description: 'Description 2',
444
+ lastMergeCommit: { commitId: 'commit-3' } // Not in our commit range
72
445
  },
73
- },
74
- pullRequestThreadContext: {
75
- changeTrackingId: 1,
76
- iterationContext: {
77
- firstComparingIteration: 1,
78
- secondComparingIteration: 1,
446
+ {
447
+ pullRequestId: 103,
448
+ title: 'PR 3',
449
+ createdBy: { displayName: 'User 3' },
450
+ creationDate: '2023-03-01',
451
+ closedDate: '2023-03-02',
452
+ description: 'Description 3',
453
+ lastMergeCommit: { commitId: 'commit-2' }
454
+ }
455
+ ]
456
+ };
457
+
458
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockPullRequests);
459
+
460
+ // Act
461
+ const result = await gitDataProvider.GetPullRequestsInCommitRangeWithoutLinkedItems(
462
+ mockProjectId,
463
+ mockRepoId,
464
+ mockCommits
465
+ );
466
+
467
+ // Assert
468
+ expect(TFSServices.getItemContent).toHaveBeenCalledWith(
469
+ expect.stringContaining(`${mockOrgUrl}${mockProjectId}/_apis/git/repositories/${mockRepoId}/pullrequests`),
470
+ mockToken,
471
+ 'get'
472
+ );
473
+ expect(result).toHaveLength(2);
474
+ expect(result[0].pullRequestId).toBe(101);
475
+ expect(result[1].pullRequestId).toBe(103);
476
+ expect(logger.info).toHaveBeenCalledWith(
477
+ expect.stringContaining('filtered in commit range 2 pullrequests')
478
+ );
479
+ });
480
+
481
+ it('should return empty array when no matching pull requests', async () => {
482
+ // Arrange
483
+ const mockCommits = {
484
+ value: [
485
+ { commitId: 'commit-999' } // Not matching any PRs
486
+ ]
487
+ };
488
+
489
+ const mockPullRequests = {
490
+ count: 2,
491
+ value: [
492
+ {
493
+ pullRequestId: 101,
494
+ lastMergeCommit: { commitId: 'commit-1' }
79
495
  },
80
- },
496
+ {
497
+ pullRequestId: 102,
498
+ lastMergeCommit: { commitId: 'commit-2' }
499
+ }
500
+ ]
501
+ };
502
+
503
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockPullRequests);
504
+
505
+ // Act
506
+ const result = await gitDataProvider.GetPullRequestsInCommitRangeWithoutLinkedItems(
507
+ mockProjectId,
508
+ mockRepoId,
509
+ mockCommits
510
+ );
511
+
512
+ // Assert
513
+ expect(result).toHaveLength(0);
514
+ });
515
+
516
+ it('should handle API errors appropriately', async () => {
517
+ // Arrange
518
+ const mockCommits = { value: [{ commitId: 'commit-1' }] };
519
+ const mockError = new Error('API Error');
520
+ (TFSServices.getItemContent as jest.Mock).mockRejectedValueOnce(mockError);
521
+
522
+ // Act & Assert
523
+ await expect(gitDataProvider.GetPullRequestsInCommitRangeWithoutLinkedItems(
524
+ mockProjectId,
525
+ mockRepoId,
526
+ mockCommits
527
+ )).rejects.toThrow('API Error');
528
+ });
529
+ });
530
+
531
+ describe('GitDataProvider - GetRepoReferences', () => {
532
+ let gitDataProvider: GitDataProvider;
533
+ const mockOrgUrl = 'https://dev.azure.com/orgname/';
534
+ const mockToken = 'mock-token';
535
+ const mockProjectId = 'project-123';
536
+ const mockRepoId = 'repo-456';
537
+
538
+ beforeEach(() => {
539
+ jest.clearAllMocks();
540
+ gitDataProvider = new GitDataProvider(mockOrgUrl, mockToken);
541
+ });
542
+
543
+ it('should return formatted tags when gitObjectType is "tag"', async () => {
544
+ // Arrange
545
+ const mockTags = {
546
+ count: 2,
547
+ value: [
548
+ { name: 'refs/tags/v1.0.0', objectId: 'tag-1' },
549
+ { name: 'refs/tags/v2.0.0', objectId: 'tag-2' }
550
+ ]
81
551
  };
82
- let gitDataProvider = await dgDataProviderAzureDevOps.getGitDataProvider();
83
- let json = await gitDataProvider.CreatePullRequestComment(
84
- "tests",
85
- "68f2aee7-0864-458e-93ce-320303a080ed",
86
- 73,
87
- data
88
- );
89
- expect(json.comment).toBeDefined;
90
- });
91
- test("should return commits with linked items in date range", async () => {
92
- let gitDataProvider = await dgDataProviderAzureDevOps.getGitDataProvider();
93
- let commitRange = await gitDataProvider.GetCommitsInDateRange(
94
- "Azuretraining",
95
- "b77bccb5-38de-4dca-9dcb-b0f8046bc045",
96
- "2016-10-21T12:51:51Z",
97
- "2024-10-24T12:51:51Z",
98
- "main"
99
- );
100
- let items = await gitDataProvider.GetItemsInCommitRange(
101
- "Azuretraining",
102
- "b77bccb5-38de-4dca-9dcb-b0f8046bc045",
103
- commitRange
104
- );
105
- expect(items[0].workItem).toBeDefined();
106
- });
107
- test("should return source trigger commit for pipline", async () => {
108
- let gitDataProvider = await dgDataProviderAzureDevOps.getGitDataProvider();
109
- let json = await gitDataProvider.GetCommitForPipeline(
110
- "tests",
111
- 248
112
- );
113
- expect(json).toBe("59d59691ee002815e7aa774f0a90ef28a6e4708f");
114
- });
115
- test("should return commits in commit range", async () => {
116
- let gitDataProvider = await dgDataProviderAzureDevOps.getGitDataProvider();
117
- let json = await gitDataProvider.GetCommitsInCommitRange(
118
- "tests",
119
- "68f2aee7-0864-458e-93ce-320303a080ed",
120
- "4ce7f96f74f10bb60d27d7180a8d1bd44da1ffac",
121
- "e46f8023be49db94b5cf188b41f7ba9db6fd8274"
122
- );
123
- expect(json.count).toBeGreaterThan(0);
124
- });
125
- test("should return items linked in build range", async () => {
126
- let gitDataProvider = await dgDataProviderAzureDevOps.getGitDataProvider();
127
- let json = await gitDataProvider.GetItemsForPipelinesRange(
128
- "tests",
129
- 244,
130
- 244
131
- );
132
- expect(json.length).toBeGreaterThan(0);
133
- });
134
- test("should return commits range between dates ", async () => {
135
- let gitDataProvider = await dgDataProviderAzureDevOps.getGitDataProvider();
136
- let json = await gitDataProvider.GetCommitsInDateRange(
137
- "tests",
138
- "68f2aee7-0864-458e-93ce-320303a080ed",
139
- "2009-11-30T12:51:51Z",
140
- "2021-11-30T12:51:51Z"
141
- );
142
- expect(json.count).toBeGreaterThanOrEqual(14);
143
- });
144
- test("should return all commits for repo ", async ()=>{
145
- let gitDataProvider = await dgDataProviderAzureDevOps.getGitDataProvider();
146
- let json = await gitDataProvider.GetCommitsForRepo(
147
- "tests",
148
- "68f2aee7-0864-458e-93ce-320303a080ed",
149
- "master"
150
- );
151
- expect(json.count).toBeGreaterThanOrEqual(0);
152
- })
153
- test("should return all pullrequests for repo ", async ()=>{
154
- let gitDataProvider = await dgDataProviderAzureDevOps.getGitDataProvider();
155
- let json = await gitDataProvider.GetPullRequestsForRepo(
156
- "tests",
157
- "68f2aee7-0864-458e-93ce-320303a080ed"
158
- );
159
- expect(json.count).toBeGreaterThanOrEqual(0);
160
- })
161
-
162
- test("should return all pullrequests for repo with Given PrId ", async ()=>{
163
- let gitDataProvider = await dgDataProviderAzureDevOps.getGitDataProvider();
164
- let json = await gitDataProvider.GetItemsInPullRequestRange(
165
- "tests",
166
- "68f2aee7-0864-458e-93ce-320303a080ed",
167
- [73,74]
168
- );
169
- expect(json.count).toBeGreaterThanOrEqual(0);
170
- })
171
-
172
- test("should return branches of repository ", async ()=>{
173
- let gitDataProvider = await dgDataProviderAzureDevOps.getGitDataProvider();
174
- let json = await gitDataProvider.GetRepoBranches(
175
- "tests",
176
- "68f2aee7-0864-458e-93ce-320303a080ed",
177
- );
178
- expect(json.count).toBeGreaterThanOrEqual(0);
179
- })
180
-
181
- }); //describe
182
-
183
- test("should return pull requests in commit range without linked items", async () => {
184
- let gitDataProvider = await dgDataProviderAzureDevOps.getGitDataProvider();
185
-
186
- // Get the commit range using the date range
187
- let commitRange = await gitDataProvider.GetCommitsInDateRange(
188
- "Azuretraining",
189
- "b77bccb5-38de-4dca-9dcb-b0f8046bc045",
190
- "2023-7-21T12:51:51Z",
191
- "2024-8-21T12:51:51Z",
192
- "main"
193
- );
194
-
195
- // Use the new function to get pull requests without linked items
196
- let pullRequests = await gitDataProvider.GetPullRequestsInCommitRangeWithoutLinkedItems(
197
- "Azuretraining",
198
- "b77bccb5-38de-4dca-9dcb-b0f8046bc045",
199
- commitRange
200
- );
201
-
202
- // Print the pull requests
203
- console.log("Pull Requests:", pullRequests);
204
-
205
- expect(pullRequests).toBeDefined();
206
- expect(pullRequests.length).toBeGreaterThan(0);
552
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockTags);
553
+
554
+ // Act
555
+ const result = await gitDataProvider.GetRepoReferences(
556
+ mockProjectId,
557
+ mockRepoId,
558
+ 'tag'
559
+ );
560
+
561
+ // Assert
562
+ expect(TFSServices.getItemContent).toHaveBeenCalledWith(
563
+ `${mockOrgUrl}${mockProjectId}/_apis/git/repositories/${mockRepoId}/refs/tags?api-version=5.1`,
564
+ mockToken,
565
+ 'get'
566
+ );
567
+ expect(result).toHaveLength(2);
568
+ expect(result[0].name).toBe('v1.0.0');
569
+ expect(result[0].value).toBe('refs/tags/v1.0.0');
570
+ expect(result[1].name).toBe('v2.0.0');
571
+ expect(result[1].value).toBe('refs/tags/v2.0.0');
572
+ });
573
+
574
+ it('should return formatted branches when gitObjectType is "branch"', async () => {
575
+ // Arrange
576
+ const mockBranches = {
577
+ count: 2,
578
+ value: [
579
+ { name: 'refs/heads/main', objectId: 'branch-1' },
580
+ { name: 'refs/heads/develop', objectId: 'branch-2' }
581
+ ]
582
+ };
583
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockBranches);
584
+
585
+ // Act
586
+ const result = await gitDataProvider.GetRepoReferences(
587
+ mockProjectId,
588
+ mockRepoId,
589
+ 'branch'
590
+ );
591
+
592
+ // Assert
593
+ expect(TFSServices.getItemContent).toHaveBeenCalledWith(
594
+ `${mockOrgUrl}${mockProjectId}/_apis/git/repositories/${mockRepoId}/refs/heads?api-version=5.1`,
595
+ mockToken,
596
+ 'get'
597
+ );
598
+ expect(result).toHaveLength(2);
599
+ expect(result[0].name).toBe('main');
600
+ expect(result[0].value).toBe('refs/heads/main');
601
+ expect(result[1].name).toBe('develop');
602
+ expect(result[1].value).toBe('refs/heads/develop');
603
+ });
604
+
605
+ it('should throw error for unsupported git object type', async () => {
606
+ // Act & Assert
607
+ await expect(gitDataProvider.GetRepoReferences(
608
+ mockProjectId,
609
+ mockRepoId,
610
+ 'invalid-type'
611
+ )).rejects.toThrow('Unsupported git object type: invalid-type');
612
+ });
613
+
614
+ it('should return empty array when no references exist', async () => {
615
+ // Arrange
616
+ const mockEmptyRefs = { count: 0, value: [] };
617
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockEmptyRefs);
618
+
619
+ // Act
620
+ const result = await gitDataProvider.GetRepoReferences(
621
+ mockProjectId,
622
+ mockRepoId,
623
+ 'branch'
624
+ );
625
+
626
+ // Assert
627
+ expect(result).toEqual([]);
628
+ });
207
629
  });
630
+
631
+ describe('GitDataProvider - GetJsonFileFromGitRepo', () => {
632
+ let gitDataProvider: GitDataProvider;
633
+ const mockOrgUrl = 'https://dev.azure.com/orgname/';
634
+ const mockToken = 'mock-token';
635
+ const mockProjectName = 'project-123';
636
+ const mockRepoName = 'repo-456';
637
+ const mockFilePath = 'config/settings.json';
638
+
639
+ beforeEach(() => {
640
+ jest.clearAllMocks();
641
+ gitDataProvider = new GitDataProvider(mockOrgUrl, mockToken);
642
+ });
643
+
644
+ it('should parse and return JSON content when file exists', async () => {
645
+ // Arrange
646
+ const mockJsonContent = { setting1: 'value1', setting2: 'value2' };
647
+ const mockResponse = { content: JSON.stringify(mockJsonContent) };
648
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockResponse);
649
+
650
+ // Act
651
+ const result = await gitDataProvider.GetJsonFileFromGitRepo(
652
+ mockProjectName,
653
+ mockRepoName,
654
+ mockFilePath
655
+ );
656
+
657
+ // Assert
658
+ expect(TFSServices.getItemContent).toHaveBeenCalledWith(
659
+ `${mockOrgUrl}${mockProjectName}/_apis/git/repositories/${mockRepoName}/items?path=${mockFilePath}&includeContent=true`,
660
+ mockToken,
661
+ 'get'
662
+ );
663
+ expect(result).toEqual(mockJsonContent);
664
+ });
665
+
666
+ it('should throw an error for invalid JSON content', async () => {
667
+ // Arrange
668
+ const mockInvalidJson = { content: '{ invalid json' };
669
+ (TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce(mockInvalidJson);
670
+
671
+ // Act & Assert
672
+ await expect(gitDataProvider.GetJsonFileFromGitRepo(
673
+ mockProjectName,
674
+ mockRepoName,
675
+ mockFilePath
676
+ )).rejects.toThrow(SyntaxError);
677
+ });
678
+
679
+ it('should handle API errors appropriately', async () => {
680
+ // Arrange
681
+ const mockError = new Error('API Error');
682
+ (TFSServices.getItemContent as jest.Mock).mockRejectedValueOnce(mockError);
683
+
684
+ // Act & Assert
685
+ await expect(gitDataProvider.GetJsonFileFromGitRepo(
686
+ mockProjectName,
687
+ mockRepoName,
688
+ mockFilePath
689
+ )).rejects.toThrow('API Error');
690
+ });
691
+ });