n8n-nodes-azuredevops-advanced 0.1.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 (41) hide show
  1. package/credentials/AzureDevOpsAdvancedApi.credentials.ts +27 -0
  2. package/dist/credentials/AzureDevOpsAdvancedApi.credentials.d.ts +7 -0
  3. package/dist/credentials/AzureDevOpsAdvancedApi.credentials.js +31 -0
  4. package/dist/nodes/AzureDevOpsAdvanced/AzureDevOpsAdvanced.node.d.ts +5 -0
  5. package/dist/nodes/AzureDevOpsAdvanced/AzureDevOpsAdvanced.node.js +529 -0
  6. package/dist/nodes/AzureDevOpsAdvanced/GenericFunctions.d.ts +2 -0
  7. package/dist/nodes/AzureDevOpsAdvanced/GenericFunctions.js +26 -0
  8. package/dist/nodes/AzureDevOpsAdvanced/descriptions/ArtifactsDescription.d.ts +3 -0
  9. package/dist/nodes/AzureDevOpsAdvanced/descriptions/ArtifactsDescription.js +48 -0
  10. package/dist/nodes/AzureDevOpsAdvanced/descriptions/BoardDescription.d.ts +3 -0
  11. package/dist/nodes/AzureDevOpsAdvanced/descriptions/BoardDescription.js +64 -0
  12. package/dist/nodes/AzureDevOpsAdvanced/descriptions/GitDescription.d.ts +3 -0
  13. package/dist/nodes/AzureDevOpsAdvanced/descriptions/GitDescription.js +107 -0
  14. package/dist/nodes/AzureDevOpsAdvanced/descriptions/PipelineDescription.d.ts +3 -0
  15. package/dist/nodes/AzureDevOpsAdvanced/descriptions/PipelineDescription.js +64 -0
  16. package/dist/nodes/AzureDevOpsAdvanced/descriptions/PullRequestDescription.d.ts +3 -0
  17. package/dist/nodes/AzureDevOpsAdvanced/descriptions/PullRequestDescription.js +298 -0
  18. package/dist/nodes/AzureDevOpsAdvanced/descriptions/ServiceHookDescription.d.ts +3 -0
  19. package/dist/nodes/AzureDevOpsAdvanced/descriptions/ServiceHookDescription.js +73 -0
  20. package/dist/nodes/AzureDevOpsAdvanced/descriptions/TestPlanDescription.d.ts +3 -0
  21. package/dist/nodes/AzureDevOpsAdvanced/descriptions/TestPlanDescription.js +66 -0
  22. package/dist/nodes/AzureDevOpsAdvanced/descriptions/TfvcDescription.d.ts +3 -0
  23. package/dist/nodes/AzureDevOpsAdvanced/descriptions/TfvcDescription.js +50 -0
  24. package/dist/nodes/AzureDevOpsAdvanced/descriptions/WikiDescription.d.ts +3 -0
  25. package/dist/nodes/AzureDevOpsAdvanced/descriptions/WikiDescription.js +82 -0
  26. package/dist/nodes/AzureDevOpsAdvanced/descriptions/WorkItemDescription.d.ts +3 -0
  27. package/dist/nodes/AzureDevOpsAdvanced/descriptions/WorkItemDescription.js +189 -0
  28. package/nodes/AzureDevOpsAdvanced/AzureDevOpsAdvanced.node.ts +541 -0
  29. package/nodes/AzureDevOpsAdvanced/GenericFunctions.ts +35 -0
  30. package/nodes/AzureDevOpsAdvanced/azureDevOps.svg +12 -0
  31. package/nodes/AzureDevOpsAdvanced/descriptions/ArtifactsDescription.ts +48 -0
  32. package/nodes/AzureDevOpsAdvanced/descriptions/BoardDescription.ts +64 -0
  33. package/nodes/AzureDevOpsAdvanced/descriptions/GitDescription.ts +108 -0
  34. package/nodes/AzureDevOpsAdvanced/descriptions/PipelineDescription.ts +64 -0
  35. package/nodes/AzureDevOpsAdvanced/descriptions/PullRequestDescription.ts +298 -0
  36. package/nodes/AzureDevOpsAdvanced/descriptions/ServiceHookDescription.ts +73 -0
  37. package/nodes/AzureDevOpsAdvanced/descriptions/TestPlanDescription.ts +66 -0
  38. package/nodes/AzureDevOpsAdvanced/descriptions/TfvcDescription.ts +50 -0
  39. package/nodes/AzureDevOpsAdvanced/descriptions/WikiDescription.ts +82 -0
  40. package/nodes/AzureDevOpsAdvanced/descriptions/WorkItemDescription.ts +189 -0
  41. package/package.json +54 -0
@@ -0,0 +1,27 @@
1
+ import { ICredentialType, INodeProperties } from 'n8n-workflow';
2
+
3
+ export class AzureDevOpsAdvancedApi implements ICredentialType {
4
+ name = 'azureDevOpsAdvancedApi';
5
+ displayName = 'Azure DevOps Advanced API';
6
+ // Belgelendirme linkine doğrudan PAT nasıl alınır yönlendirilebilir
7
+ documentationUrl = 'https://n8n.io/integrations/azure-devops';
8
+ properties: INodeProperties[] = [
9
+ {
10
+ displayName: 'Organization',
11
+ name: 'organization',
12
+ type: 'string',
13
+ default: '',
14
+ required: true,
15
+ description: 'The Azure DevOps organization name (e.g. dev.azure.com/{organization})',
16
+ },
17
+ {
18
+ displayName: 'Personal Access Token (PAT)',
19
+ name: 'pat',
20
+ type: 'string',
21
+ typeOptions: { password: true },
22
+ default: '',
23
+ required: true,
24
+ description: 'Tüm repolara Read/Write yetkilendirmesi olan Azure DevOps PAT anahtarınız',
25
+ },
26
+ ];
27
+ }
@@ -0,0 +1,7 @@
1
+ import { ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class AzureDevOpsAdvancedApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ properties: INodeProperties[];
7
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AzureDevOpsAdvancedApi = void 0;
4
+ class AzureDevOpsAdvancedApi {
5
+ constructor() {
6
+ this.name = 'azureDevOpsAdvancedApi';
7
+ this.displayName = 'Azure DevOps Advanced API';
8
+ // Belgelendirme linkine doğrudan PAT nasıl alınır yönlendirilebilir
9
+ this.documentationUrl = 'https://n8n.io/integrations/azure-devops';
10
+ this.properties = [
11
+ {
12
+ displayName: 'Organization',
13
+ name: 'organization',
14
+ type: 'string',
15
+ default: '',
16
+ required: true,
17
+ description: 'The Azure DevOps organization name (e.g. dev.azure.com/{organization})',
18
+ },
19
+ {
20
+ displayName: 'Personal Access Token (PAT)',
21
+ name: 'pat',
22
+ type: 'string',
23
+ typeOptions: { password: true },
24
+ default: '',
25
+ required: true,
26
+ description: 'Tüm repolara Read/Write yetkilendirmesi olan Azure DevOps PAT anahtarınız',
27
+ },
28
+ ];
29
+ }
30
+ }
31
+ exports.AzureDevOpsAdvancedApi = AzureDevOpsAdvancedApi;
@@ -0,0 +1,5 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class AzureDevOpsAdvanced implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,529 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AzureDevOpsAdvanced = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const GenericFunctions_1 = require("./GenericFunctions");
6
+ const GitDescription_1 = require("./descriptions/GitDescription");
7
+ const PipelineDescription_1 = require("./descriptions/PipelineDescription");
8
+ const WorkItemDescription_1 = require("./descriptions/WorkItemDescription");
9
+ const PullRequestDescription_1 = require("./descriptions/PullRequestDescription");
10
+ const TestPlanDescription_1 = require("./descriptions/TestPlanDescription");
11
+ const ServiceHookDescription_1 = require("./descriptions/ServiceHookDescription");
12
+ const WikiDescription_1 = require("./descriptions/WikiDescription");
13
+ const ArtifactsDescription_1 = require("./descriptions/ArtifactsDescription");
14
+ const BoardDescription_1 = require("./descriptions/BoardDescription");
15
+ class AzureDevOpsAdvanced {
16
+ constructor() {
17
+ this.description = {
18
+ displayName: 'Azure DevOps Advanced',
19
+ name: 'azureDevOpsAdvanced',
20
+ icon: 'file:azureDevOps.svg', // Icon expected here if deployed directly, maybe fallback to text/color if none provided.
21
+ group: ['transform'],
22
+ version: 1,
23
+ subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
24
+ description: 'Kapsamlı yerel Azure DevOps eklentisi',
25
+ defaults: { name: 'Azure DevOps Advanced' },
26
+ inputs: ['main'],
27
+ outputs: ['main'],
28
+ credentials: [
29
+ { name: 'azureDevOpsAdvancedApi', required: true }
30
+ ],
31
+ properties: [
32
+ {
33
+ displayName: 'Resource',
34
+ name: 'resource',
35
+ type: 'options',
36
+ noDataExpression: true,
37
+ options: [
38
+ { name: 'Git Repositories', value: 'git' },
39
+ { name: 'TFVC Repositories', value: 'tfvc' },
40
+ { name: 'Pipelines (CI/CD)', value: 'pipeline' },
41
+ { name: 'Work Items (Boards)', value: 'workItem' },
42
+ { name: 'Pull Requests', value: 'pullRequest' },
43
+ { name: 'Test Plans (QA)', value: 'testPlan' },
44
+ { name: 'Service Hooks (Webhooks)', value: 'serviceHook' },
45
+ { name: 'Wiki', value: 'wiki' },
46
+ { name: 'Artifacts', value: 'artifacts' },
47
+ { name: 'Boards & Iterations', value: 'boards' },
48
+ ],
49
+ default: 'git',
50
+ },
51
+ ...GitDescription_1.gitOperations,
52
+ ...GitDescription_1.gitFields,
53
+ ...PipelineDescription_1.pipelineOperations,
54
+ ...PipelineDescription_1.pipelineFields,
55
+ ...WorkItemDescription_1.workItemOperations,
56
+ ...WorkItemDescription_1.workItemFields,
57
+ ...PullRequestDescription_1.pullRequestOperations,
58
+ ...PullRequestDescription_1.pullRequestFields,
59
+ ...TestPlanDescription_1.testPlanOperations,
60
+ ...TestPlanDescription_1.testPlanFields,
61
+ ...ServiceHookDescription_1.serviceHookOperations,
62
+ ...ServiceHookDescription_1.serviceHookFields,
63
+ ...WikiDescription_1.wikiOperations,
64
+ ...WikiDescription_1.wikiFields,
65
+ ...ArtifactsDescription_1.artifactsOperations,
66
+ ...ArtifactsDescription_1.artifactsFields,
67
+ ...BoardDescription_1.boardOperations,
68
+ ...BoardDescription_1.boardFields,
69
+ ],
70
+ };
71
+ }
72
+ async execute() {
73
+ var _a, _b, _c, _d;
74
+ const items = this.getInputData();
75
+ const returnData = [];
76
+ const resource = this.getNodeParameter('resource', 0);
77
+ const operation = this.getNodeParameter('operation', 0);
78
+ for (let i = 0; i < items.length; i++) {
79
+ try {
80
+ const project = this.getNodeParameter('project', i);
81
+ let responseData;
82
+ // ===== GIT RESOURCE =====
83
+ if (resource === 'git') {
84
+ if (operation === 'listRepos') {
85
+ const endpoint = `${project}/_apis/git/repositories?api-version=7.1`;
86
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
87
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
88
+ }
89
+ else if (operation === 'getFile') {
90
+ const repoId = this.getNodeParameter('repositoryId', i);
91
+ const filePath = this.getNodeParameter('filePath', i);
92
+ const endpoint = `${project}/_apis/git/repositories/${repoId}/items?scopePath=${filePath}&api-version=7.1`;
93
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
94
+ }
95
+ else if (operation === 'createBranch') {
96
+ const repoId = this.getNodeParameter('repositoryId', i);
97
+ const branchName = this.getNodeParameter('branchName', i);
98
+ // To create a branch, we need the oldObjectID from the repo (usually main/master)
99
+ // Simplified implementation for the boilerplate. Requires fetching refs first.
100
+ const endpoint = `${project}/_apis/git/repositories/${repoId}/refs?filter=heads/main&api-version=7.1`;
101
+ const refResponse = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
102
+ const oldObjectId = ((_b = (_a = refResponse === null || refResponse === void 0 ? void 0 : refResponse.value) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.objectId) || "0000000000000000000000000000000000000000";
103
+ const createEndpoint = `${project}/_apis/git/repositories/${repoId}/refs?api-version=7.1`;
104
+ const body = [{ name: branchName, newObjectId: oldObjectId, oldObjectId: "0000000000000000000000000000000000000000" }];
105
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'POST', createEndpoint, body);
106
+ }
107
+ else if (operation === 'pushCommit') {
108
+ const repoId = this.getNodeParameter('repositoryId', i);
109
+ const branchName = this.getNodeParameter('branchName', i);
110
+ const commitMessage = this.getNodeParameter('commitMessage', i);
111
+ // Requires complex PUSH structure with base64 encoded strings for files.
112
+ // Simplified placeholder structure
113
+ const endpoint = `${project}/_apis/git/repositories/${repoId}/pushes?api-version=7.1`;
114
+ const body = {
115
+ refUpdates: [{ name: branchName, oldObjectId: "0000000000000000000000000000000000000000" }],
116
+ commits: [{ comment: commitMessage, changes: [] }]
117
+ };
118
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'POST', endpoint, body);
119
+ }
120
+ }
121
+ // ===== PIPELINE RESOURCE =====
122
+ else if (resource === 'pipeline') {
123
+ if (operation === 'list') {
124
+ const endpoint = `${project}/_apis/pipelines?api-version=7.1-preview.1`;
125
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
126
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
127
+ }
128
+ else if (operation === 'run') {
129
+ const pipelineId = this.getNodeParameter('pipelineId', i);
130
+ const endpoint = `${project}/_apis/pipelines/${pipelineId}/runs?api-version=7.1-preview.1`;
131
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'POST', endpoint, {});
132
+ }
133
+ else if (operation === 'getLogs') {
134
+ const pipelineId = this.getNodeParameter('pipelineId', i);
135
+ const runId = this.getNodeParameter('runId', i);
136
+ const endpoint = `${project}/_apis/pipelines/${pipelineId}/runs/${runId}/logs?api-version=7.1-preview.1`;
137
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
138
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.logs) || (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
139
+ }
140
+ else if (operation === 'cancelRun') {
141
+ const pipelineId = this.getNodeParameter('pipelineId', i);
142
+ const runId = this.getNodeParameter('runId', i);
143
+ const endpoint = `${project}/_apis/pipelines/${pipelineId}/runs/${runId}?api-version=7.1-preview.1`;
144
+ const body = { state: "canceling" };
145
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'PATCH', endpoint, body);
146
+ }
147
+ }
148
+ // ===== TFVC RESOURCE =====
149
+ else if (resource === 'tfvc') {
150
+ if (operation === 'listRepos') {
151
+ const endpoint = `${project}/_apis/tfvc/branches?api-version=7.1`;
152
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
153
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
154
+ }
155
+ else if (operation === 'getFile') {
156
+ const filePath = this.getNodeParameter('filePath', i);
157
+ const endpoint = `${project}/_apis/tfvc/items?path=${filePath}&api-version=7.1`;
158
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
159
+ }
160
+ }
161
+ // ===== WORK ITEM RESOURCE =====
162
+ else if (resource === 'workItem') {
163
+ if (operation === 'get') {
164
+ const workItemId = this.getNodeParameter('workItemId', i);
165
+ const endpoint = `${project}/_apis/wit/workitems/${workItemId}?api-version=7.1`;
166
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
167
+ }
168
+ else if (operation === 'listAll') {
169
+ const endpoint = `${project}/_apis/wit/wiql?api-version=7.1`;
170
+ const wiqlQuery = { query: `Select [System.Id], [System.Title], [System.State] From WorkItems Where [System.TeamProject] = '${project}'` };
171
+ const idsResponse = await GenericFunctions_1.azureApiRequest.call(this, 'POST', endpoint, wiqlQuery);
172
+ const idsArray = (_c = idsResponse === null || idsResponse === void 0 ? void 0 : idsResponse.workItems) === null || _c === void 0 ? void 0 : _c.map((wi) => wi.id);
173
+ if (idsArray && idsArray.length > 0) {
174
+ const workItemIds = idsArray.join(',');
175
+ const bulkEndpoint = `${project}/_apis/wit/workitems?ids=${workItemIds}&api-version=7.1`;
176
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', bulkEndpoint);
177
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
178
+ }
179
+ else {
180
+ responseData = [];
181
+ }
182
+ }
183
+ else if (operation === 'create' || operation === 'update') {
184
+ const isUpdate = operation === 'update';
185
+ const endpoint = isUpdate
186
+ ? `${project}/_apis/wit/workitems/${this.getNodeParameter('workItemId', i)}?api-version=7.1`
187
+ : `${project}/_apis/wit/workitems/$${this.getNodeParameter('workItemType', i)}?api-version=7.1`;
188
+ // Azure DevOps API expects JSON Patch format application/json-patch+json
189
+ const bodyData = [];
190
+ const mapPropertyToPatch = (path, value) => {
191
+ if (value !== undefined && value !== '') {
192
+ bodyData.push({ op: "add", path: `/fields/${path}`, value: value });
193
+ }
194
+ };
195
+ if (!isUpdate) {
196
+ mapPropertyToPatch('System.Title', this.getNodeParameter('title', i));
197
+ }
198
+ const additionalFields = this.getNodeParameter('additionalFields', i);
199
+ if (Object.keys(additionalFields).length) {
200
+ mapPropertyToPatch('System.Description', additionalFields.description);
201
+ mapPropertyToPatch('System.AssignedTo', additionalFields.assignedTo);
202
+ mapPropertyToPatch('System.State', additionalFields.state);
203
+ mapPropertyToPatch('Microsoft.VSTS.Common.Priority', additionalFields.priority);
204
+ mapPropertyToPatch('System.Tags', additionalFields.tags);
205
+ if ((_d = additionalFields.customFieldsUi) === null || _d === void 0 ? void 0 : _d.customFieldsValues) {
206
+ for (const customField of additionalFields.customFieldsUi.customFieldsValues) {
207
+ mapPropertyToPatch(customField.fieldId, customField.fieldValue);
208
+ }
209
+ }
210
+ }
211
+ const credentials = await this.getCredentials('azureDevOpsAdvancedApi');
212
+ const token = Buffer.from(`:${credentials.pat}`).toString('base64');
213
+ const baseUrl = `https://dev.azure.com/${credentials.organization}`;
214
+ responseData = await this.helpers.request({
215
+ method: isUpdate ? 'PATCH' : 'POST',
216
+ uri: `${baseUrl}/${endpoint}`,
217
+ body: bodyData,
218
+ headers: {
219
+ 'Content-Type': 'application/json-patch+json',
220
+ Authorization: `Basic ${token}`,
221
+ },
222
+ json: true,
223
+ });
224
+ }
225
+ else if (operation === 'listUsers') {
226
+ // Azure Graph API / Core API üzerinden user listesi çekilir
227
+ const endpoint = `_apis/graph/users?api-version=7.1-preview.1`;
228
+ const credentials = await this.getCredentials('azureDevOpsAdvancedApi');
229
+ const baseUrl = `https://vssps.dev.azure.com/${credentials.organization}`;
230
+ const token = Buffer.from(`:${credentials.pat}`).toString('base64');
231
+ responseData = await this.helpers.request({
232
+ method: 'GET',
233
+ uri: `${baseUrl}/${endpoint}`,
234
+ headers: {
235
+ 'Content-Type': 'application/json',
236
+ Authorization: `Basic ${token}`,
237
+ },
238
+ json: true,
239
+ });
240
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
241
+ }
242
+ else if (operation === 'listTags') {
243
+ // Project bazlı tag listesi
244
+ const endpoint = `${project}/_apis/wit/tags?api-version=7.1-preview.1`;
245
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
246
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
247
+ }
248
+ }
249
+ // ===== PULL REQUEST RESOURCE =====
250
+ else if (resource === 'pullRequest') {
251
+ const repositoryId = this.getNodeParameter('repositoryId', i);
252
+ if (operation === 'get') {
253
+ const pullRequestId = this.getNodeParameter('pullRequestId', i);
254
+ const endpoint = `${project}/_apis/git/repositories/${repositoryId}/pullrequests/${pullRequestId}?api-version=7.1`;
255
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
256
+ }
257
+ else if (operation === 'getComments') {
258
+ const pullRequestId = this.getNodeParameter('pullRequestId', i);
259
+ const endpoint = `${project}/_apis/git/repositories/${repositoryId}/pullRequests/${pullRequestId}/threads?api-version=7.1`;
260
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
261
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
262
+ }
263
+ else if (operation === 'list') {
264
+ const listOptions = this.getNodeParameter('listOptions', i);
265
+ let endpoint = `${project}/_apis/git/repositories/${repositoryId}/pullrequests?api-version=7.1`;
266
+ if (listOptions) {
267
+ if (listOptions.status && listOptions.status !== 'all') {
268
+ endpoint += `&searchCriteria.status=${listOptions.status}`;
269
+ }
270
+ else if (listOptions.status === 'all') {
271
+ endpoint += `&searchCriteria.status=all`;
272
+ }
273
+ if (listOptions.creatorId)
274
+ endpoint += `&searchCriteria.creatorId=${listOptions.creatorId}`;
275
+ if (listOptions.reviewerId)
276
+ endpoint += `&searchCriteria.reviewerId=${listOptions.reviewerId}`;
277
+ if (listOptions.sourceRefName)
278
+ endpoint += `&searchCriteria.sourceRefName=${listOptions.sourceRefName}`;
279
+ if (listOptions.targetRefName)
280
+ endpoint += `&searchCriteria.targetRefName=${listOptions.targetRefName}`;
281
+ if (listOptions.top)
282
+ endpoint += `&$top=${listOptions.top}`;
283
+ }
284
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
285
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
286
+ }
287
+ else if (operation === 'create') {
288
+ const sourceRefName = this.getNodeParameter('sourceRefName', i);
289
+ const targetRefName = this.getNodeParameter('targetRefName', i);
290
+ const title = this.getNodeParameter('title', i);
291
+ const additionalFields = this.getNodeParameter('additionalFields', i);
292
+ const body = {
293
+ sourceRefName,
294
+ targetRefName,
295
+ title,
296
+ };
297
+ if (additionalFields) {
298
+ if (additionalFields.description)
299
+ body.description = additionalFields.description;
300
+ if (additionalFields.isDraft)
301
+ body.isDraft = additionalFields.isDraft;
302
+ if (additionalFields.reviewers) {
303
+ body.reviewers = additionalFields.reviewers.split(',').map((id) => ({ id: id.trim() }));
304
+ }
305
+ if (additionalFields.workItemIds) {
306
+ body.workItems = additionalFields.workItemIds.split(',').map((id) => ({ id: id.trim() }));
307
+ }
308
+ }
309
+ const endpoint = `${project}/_apis/git/repositories/${repositoryId}/pullrequests?api-version=7.1`;
310
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'POST', endpoint, body);
311
+ }
312
+ else if (operation === 'update') {
313
+ const pullRequestId = this.getNodeParameter('pullRequestId', i);
314
+ const updateFields = this.getNodeParameter('updateFields', i);
315
+ const body = {};
316
+ if (updateFields) {
317
+ if (updateFields.title)
318
+ body.title = updateFields.title;
319
+ if (updateFields.description)
320
+ body.description = updateFields.description;
321
+ if (updateFields.status)
322
+ body.status = updateFields.status;
323
+ // check if there are completion options
324
+ const hasCompletionOption = updateFields.mergeStrategy || updateFields.deleteSourceBranch !== undefined || updateFields.transitionWorkItems !== undefined || updateFields.bypassPolicy !== undefined || updateFields.bypassReason || updateFields.mergeCommitMessage;
325
+ if (hasCompletionOption) {
326
+ body.completionOptions = {};
327
+ if (updateFields.bypassPolicy !== undefined)
328
+ body.completionOptions.bypassPolicy = updateFields.bypassPolicy;
329
+ if (updateFields.bypassReason)
330
+ body.completionOptions.bypassReason = updateFields.bypassReason;
331
+ if (updateFields.deleteSourceBranch !== undefined)
332
+ body.completionOptions.deleteSourceBranch = updateFields.deleteSourceBranch;
333
+ if (updateFields.mergeCommitMessage)
334
+ body.completionOptions.mergeCommitMessage = updateFields.mergeCommitMessage;
335
+ if (updateFields.mergeStrategy && updateFields.mergeStrategy !== 'squash')
336
+ body.completionOptions.squashMerge = false;
337
+ else if (updateFields.mergeStrategy === 'squash')
338
+ body.completionOptions.squashMerge = true;
339
+ if (updateFields.transitionWorkItems !== undefined)
340
+ body.completionOptions.transitionWorkItems = updateFields.transitionWorkItems;
341
+ if (updateFields.mergeStrategy)
342
+ body.completionOptions.mergeStrategy = updateFields.mergeStrategy;
343
+ }
344
+ }
345
+ const endpoint = `${project}/_apis/git/repositories/${repositoryId}/pullrequests/${pullRequestId}?api-version=7.1`;
346
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'PATCH', endpoint, body);
347
+ }
348
+ }
349
+ // ===== TEST PLANS RESOURCE =====
350
+ else if (resource === 'testPlan') {
351
+ if (operation === 'listPlans') {
352
+ const endpoint = `${project}/_apis/testplan/plans?api-version=7.1-preview.1`;
353
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
354
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
355
+ }
356
+ else if (operation === 'listSuites') {
357
+ const planId = this.getNodeParameter('planId', i);
358
+ const endpoint = `${project}/_apis/testplan/Plans/${planId}/suites?api-version=7.1-preview.1`;
359
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
360
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
361
+ }
362
+ else if (operation === 'listCases') {
363
+ const planId = this.getNodeParameter('planId', i);
364
+ const suiteId = this.getNodeParameter('suiteId', i);
365
+ const endpoint = `${project}/_apis/testplan/Plans/${planId}/Suites/${suiteId}/TestCase?api-version=7.1-preview.2`;
366
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
367
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
368
+ }
369
+ else if (operation === 'listRuns') {
370
+ const endpoint = `${project}/_apis/test/runs?api-version=7.1`;
371
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
372
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
373
+ }
374
+ }
375
+ // ===== BOARDS RESOURCE =====
376
+ else if (resource === 'boards') {
377
+ const team = this.getNodeParameter('team', i);
378
+ if (operation === 'listBoards') {
379
+ const endpoint = `${project}/${team}/_apis/work/boards?api-version=7.1`;
380
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
381
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
382
+ }
383
+ else if (operation === 'listColumns') {
384
+ const boardId = this.getNodeParameter('boardId', i);
385
+ const endpoint = `${project}/${team}/_apis/work/boards/${boardId}/columns?api-version=7.1`;
386
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
387
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
388
+ }
389
+ else if (operation === 'listIterations') {
390
+ const endpoint = `${project}/${team}/_apis/work/teamsettings/iterations?api-version=7.1`;
391
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
392
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
393
+ }
394
+ }
395
+ // ===== WIKI RESOURCE =====
396
+ else if (resource === 'wiki') {
397
+ if (operation === 'list') {
398
+ const endpoint = `${project}/_apis/wiki/wikis?api-version=7.1`;
399
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
400
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
401
+ }
402
+ else if (operation === 'getPage' || operation === 'createPage' || operation === 'updatePage') {
403
+ const wikiIdentifier = this.getNodeParameter('wikiIdentifier', i);
404
+ let pagePath = this.getNodeParameter('pagePath', i);
405
+ // Prevent root path failure
406
+ if ((operation === 'createPage' || operation === 'updatePage') && (pagePath === '/' || !pagePath)) {
407
+ throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: "The provided path value is either null, empty or wiki root. Please provide a valid page path like /MyNewPage" });
408
+ }
409
+ // Ensure slash prefix
410
+ if (!pagePath.startsWith('/'))
411
+ pagePath = '/' + pagePath;
412
+ const endpoint = `${project}/_apis/wiki/wikis/${wikiIdentifier}/pages?path=${pagePath}&api-version=7.1`;
413
+ if (operation === 'getPage') {
414
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
415
+ }
416
+ else if (operation === 'createPage') {
417
+ const content = this.getNodeParameter('content', i);
418
+ const body = { content };
419
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'PUT', endpoint, body);
420
+ }
421
+ else if (operation === 'updatePage') {
422
+ const content = this.getNodeParameter('content', i);
423
+ const credentials = await this.getCredentials('azureDevOpsAdvancedApi');
424
+ const baseUrl = `https://dev.azure.com/${credentials.organization}`;
425
+ const token = Buffer.from(`:${credentials.pat}`).toString('base64');
426
+ // Get ETag first to satisfy Azure DevOps Update requirements
427
+ const getResponse = await this.helpers.request({
428
+ method: 'GET',
429
+ uri: `${baseUrl}/${endpoint}`,
430
+ headers: { Authorization: `Basic ${token}` },
431
+ json: true,
432
+ resolveWithFullResponse: true,
433
+ });
434
+ const eTag = getResponse.headers.etag;
435
+ // Update with ETag
436
+ responseData = await this.helpers.request({
437
+ method: 'PUT',
438
+ uri: `${baseUrl}/${endpoint}`,
439
+ body: { content },
440
+ headers: {
441
+ 'Content-Type': 'application/json',
442
+ 'If-Match': eTag,
443
+ Authorization: `Basic ${token}`
444
+ },
445
+ json: true,
446
+ });
447
+ }
448
+ }
449
+ }
450
+ // ===== ARTIFACTS RESOURCE =====
451
+ else if (resource === 'artifacts') {
452
+ if (operation === 'listFeeds') {
453
+ const endpoint = `${project}/_apis/packaging/feeds?api-version=7.1-preview.1`;
454
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
455
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
456
+ }
457
+ else if (operation === 'listPackages') {
458
+ const feedId = this.getNodeParameter('feedId', i);
459
+ const endpoint = `${project}/_apis/packaging/Feeds/${feedId}/packages?api-version=7.1-preview.1`;
460
+ responseData = await GenericFunctions_1.azureApiRequest.call(this, 'GET', endpoint);
461
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
462
+ }
463
+ }
464
+ // ===== SERVICE HOOKS RESOURCE =====
465
+ else if (resource === 'serviceHook') {
466
+ if (operation === 'list') {
467
+ const endpoint = `_apis/hooks/subscriptions?api-version=7.1-preview.1`; // Collection level API
468
+ const credentials = await this.getCredentials('azureDevOpsAdvancedApi');
469
+ const baseUrl = `https://dev.azure.com/${credentials.organization}`;
470
+ const token = Buffer.from(`:${credentials.pat}`).toString('base64');
471
+ responseData = await this.helpers.request({
472
+ method: 'GET',
473
+ uri: `${baseUrl}/${endpoint}`,
474
+ headers: { 'Content-Type': 'application/json', Authorization: `Basic ${token}` },
475
+ json: true,
476
+ });
477
+ responseData = (responseData === null || responseData === void 0 ? void 0 : responseData.value) || responseData;
478
+ }
479
+ else if (operation === 'create') {
480
+ const eventType = this.getNodeParameter('eventType', i);
481
+ const consumerUrl = this.getNodeParameter('consumerUrl', i);
482
+ const endpoint = `_apis/hooks/subscriptions?api-version=7.1-preview.1`;
483
+ const body = {
484
+ publisherId: "tfs",
485
+ eventType: eventType,
486
+ resourceVersion: "1.0",
487
+ consumerId: "webHooks",
488
+ consumerActionId: "httpRequest",
489
+ publisherInputs: {
490
+ projectId: project // Using project name/id to scope the webhook
491
+ },
492
+ consumerInputs: {
493
+ url: consumerUrl
494
+ }
495
+ };
496
+ const credentials = await this.getCredentials('azureDevOpsAdvancedApi');
497
+ const baseUrl = `https://dev.azure.com/${credentials.organization}`;
498
+ const token = Buffer.from(`:${credentials.pat}`).toString('base64');
499
+ responseData = await this.helpers.request({
500
+ method: 'POST',
501
+ uri: `${baseUrl}/${endpoint}`,
502
+ body: body,
503
+ headers: { 'Content-Type': 'application/json', Authorization: `Basic ${token}` },
504
+ json: true,
505
+ });
506
+ }
507
+ }
508
+ // Sonuçların işlenmesi
509
+ if (Array.isArray(responseData)) {
510
+ returnData.push.apply(returnData, responseData.map(item => ({ json: item })));
511
+ }
512
+ else {
513
+ if (responseData) {
514
+ returnData.push({ json: responseData });
515
+ }
516
+ }
517
+ }
518
+ catch (error) {
519
+ if (this.continueOnFail()) {
520
+ returnData.push({ json: { error: error.message } });
521
+ continue;
522
+ }
523
+ throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
524
+ }
525
+ }
526
+ return [returnData];
527
+ }
528
+ }
529
+ exports.AzureDevOpsAdvanced = AzureDevOpsAdvanced;
@@ -0,0 +1,2 @@
1
+ import { IExecuteFunctions, ILoadOptionsFunctions } from 'n8n-workflow';
2
+ export declare function azureApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body?: any, query?: any): Promise<any>;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.azureApiRequest = azureApiRequest;
4
+ async function azureApiRequest(method, endpoint, body = {}, query = {}) {
5
+ const credentials = await this.getCredentials('azureDevOpsAdvancedApi');
6
+ if (!credentials) {
7
+ throw new Error('No credentials provided!');
8
+ }
9
+ const token = Buffer.from(`:${credentials.pat}`).toString('base64');
10
+ const baseUrl = `https://dev.azure.com/${credentials.organization}`;
11
+ const options = {
12
+ method,
13
+ body,
14
+ qs: query,
15
+ uri: `${baseUrl}/${endpoint}`,
16
+ headers: {
17
+ 'Content-Type': 'application/json',
18
+ Authorization: `Basic ${token}`,
19
+ },
20
+ json: true,
21
+ };
22
+ if (Object.keys(body).length === 0) {
23
+ delete options.body;
24
+ }
25
+ return this.helpers.request(options);
26
+ }
@@ -0,0 +1,3 @@
1
+ import { INodeProperties } from 'n8n-workflow';
2
+ export declare const artifactsOperations: INodeProperties[];
3
+ export declare const artifactsFields: INodeProperties[];