@paklo/core 0.8.0 → 0.10.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.
- package/dist/azure/index.d.mts +1605 -289
- package/dist/azure/index.mjs +951 -478
- package/dist/azure/index.mjs.map +1 -1
- package/dist/dependabot/index.d.mts +3 -3
- package/dist/dependabot/index.mjs +3 -4
- package/dist/{dependabot-E0nM5Xbb.mjs → dependabot-DVf7lAEG.mjs} +82 -20
- package/dist/dependabot-DVf7lAEG.mjs.map +1 -0
- package/dist/github/index.d.mts +1 -1
- package/dist/github/index.mjs +1 -1
- package/dist/{index-BWftXTYB.d.mts → index-BfwWezjJ.d.mts} +1 -1
- package/dist/{index-bwD11mTZ.d.mts → index-CFWMNvXg.d.mts} +105 -46
- package/dist/{job-DanO84YW.mjs → job-COuliaYg.mjs} +13 -16
- package/dist/{job-DanO84YW.mjs.map → job-COuliaYg.mjs.map} +1 -1
- package/dist/{logger-BqvUa-Ue.mjs → logger-3Qfh9NUj.mjs} +11 -4
- package/dist/logger-3Qfh9NUj.mjs.map +1 -0
- package/dist/logger.mjs +1 -1
- package/dist/usage.d.mts +1 -1
- package/dist/usage.mjs +1 -1
- package/package.json +5 -8
- package/dist/dependabot-E0nM5Xbb.mjs.map +0 -1
- package/dist/http/index.d.mts +0 -121
- package/dist/http/index.mjs +0 -3
- package/dist/http-D2wwAKQ-.mjs +0 -241
- package/dist/http-D2wwAKQ-.mjs.map +0 -1
- package/dist/logger-BqvUa-Ue.mjs.map +0 -1
package/dist/azure/index.mjs
CHANGED
|
@@ -1,130 +1,586 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import "
|
|
1
|
+
import { n as logger } from "../logger-3Qfh9NUj.mjs";
|
|
2
|
+
import { T as CONFIG_FILE_PATHS_AZURE, _ as DependabotPersistedPrSchema, z as parseDependabotConfig } from "../job-COuliaYg.mjs";
|
|
3
|
+
import { n as getDependencyNames, o as normalizeBranchName, s as normalizeFilePath, t as areEqual } from "../dependabot-DVf7lAEG.mjs";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import ky, { isHTTPError } from "ky";
|
|
5
6
|
import * as path from "node:path";
|
|
6
7
|
import { existsSync } from "node:fs";
|
|
7
8
|
import { readFile } from "node:fs/promises";
|
|
8
9
|
|
|
9
|
-
//#region src/azure/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
VersionControlChangeType$1[VersionControlChangeType$1["Encoding"] = 4] = "Encoding";
|
|
15
|
-
VersionControlChangeType$1[VersionControlChangeType$1["Rename"] = 8] = "Rename";
|
|
16
|
-
VersionControlChangeType$1[VersionControlChangeType$1["Delete"] = 16] = "Delete";
|
|
17
|
-
VersionControlChangeType$1[VersionControlChangeType$1["Undelete"] = 32] = "Undelete";
|
|
18
|
-
VersionControlChangeType$1[VersionControlChangeType$1["Branch"] = 64] = "Branch";
|
|
19
|
-
VersionControlChangeType$1[VersionControlChangeType$1["Merge"] = 128] = "Merge";
|
|
20
|
-
VersionControlChangeType$1[VersionControlChangeType$1["Lock"] = 256] = "Lock";
|
|
21
|
-
VersionControlChangeType$1[VersionControlChangeType$1["Rollback"] = 512] = "Rollback";
|
|
22
|
-
VersionControlChangeType$1[VersionControlChangeType$1["SourceRename"] = 1024] = "SourceRename";
|
|
23
|
-
VersionControlChangeType$1[VersionControlChangeType$1["TargetRename"] = 2048] = "TargetRename";
|
|
24
|
-
VersionControlChangeType$1[VersionControlChangeType$1["Property"] = 4096] = "Property";
|
|
25
|
-
VersionControlChangeType$1[VersionControlChangeType$1["All"] = 8191] = "All";
|
|
26
|
-
return VersionControlChangeType$1;
|
|
27
|
-
}({});
|
|
28
|
-
let GitPullRequestMergeStrategy = /* @__PURE__ */ function(GitPullRequestMergeStrategy$1) {
|
|
29
|
-
GitPullRequestMergeStrategy$1[GitPullRequestMergeStrategy$1["NoFastForward"] = 1] = "NoFastForward";
|
|
30
|
-
GitPullRequestMergeStrategy$1[GitPullRequestMergeStrategy$1["Squash"] = 2] = "Squash";
|
|
31
|
-
GitPullRequestMergeStrategy$1[GitPullRequestMergeStrategy$1["Rebase"] = 3] = "Rebase";
|
|
32
|
-
GitPullRequestMergeStrategy$1[GitPullRequestMergeStrategy$1["RebaseMerge"] = 4] = "RebaseMerge";
|
|
33
|
-
return GitPullRequestMergeStrategy$1;
|
|
34
|
-
}({});
|
|
35
|
-
let CommentThreadStatus = /* @__PURE__ */ function(CommentThreadStatus$1) {
|
|
36
|
-
CommentThreadStatus$1[CommentThreadStatus$1["Unknown"] = 0] = "Unknown";
|
|
37
|
-
CommentThreadStatus$1[CommentThreadStatus$1["Active"] = 1] = "Active";
|
|
38
|
-
CommentThreadStatus$1[CommentThreadStatus$1["Fixed"] = 2] = "Fixed";
|
|
39
|
-
CommentThreadStatus$1[CommentThreadStatus$1["WontFix"] = 3] = "WontFix";
|
|
40
|
-
CommentThreadStatus$1[CommentThreadStatus$1["Closed"] = 4] = "Closed";
|
|
41
|
-
CommentThreadStatus$1[CommentThreadStatus$1["ByDesign"] = 5] = "ByDesign";
|
|
42
|
-
CommentThreadStatus$1[CommentThreadStatus$1["Pending"] = 6] = "Pending";
|
|
43
|
-
return CommentThreadStatus$1;
|
|
44
|
-
}({});
|
|
45
|
-
let CommentType = /* @__PURE__ */ function(CommentType$1) {
|
|
46
|
-
CommentType$1[CommentType$1["Unknown"] = 0] = "Unknown";
|
|
47
|
-
CommentType$1[CommentType$1["Text"] = 1] = "Text";
|
|
48
|
-
CommentType$1[CommentType$1["CodeChange"] = 2] = "CodeChange";
|
|
49
|
-
CommentType$1[CommentType$1["System"] = 3] = "System";
|
|
50
|
-
return CommentType$1;
|
|
51
|
-
}({});
|
|
52
|
-
let ItemContentType = /* @__PURE__ */ function(ItemContentType$1) {
|
|
53
|
-
ItemContentType$1[ItemContentType$1["RawText"] = 0] = "RawText";
|
|
54
|
-
ItemContentType$1[ItemContentType$1["Base64Encoded"] = 1] = "Base64Encoded";
|
|
55
|
-
return ItemContentType$1;
|
|
56
|
-
}({});
|
|
57
|
-
let PullRequestAsyncStatus = /* @__PURE__ */ function(PullRequestAsyncStatus$1) {
|
|
58
|
-
PullRequestAsyncStatus$1[PullRequestAsyncStatus$1["NotSet"] = 0] = "NotSet";
|
|
59
|
-
PullRequestAsyncStatus$1[PullRequestAsyncStatus$1["Queued"] = 1] = "Queued";
|
|
60
|
-
PullRequestAsyncStatus$1[PullRequestAsyncStatus$1["Conflicts"] = 2] = "Conflicts";
|
|
61
|
-
PullRequestAsyncStatus$1[PullRequestAsyncStatus$1["Succeeded"] = 3] = "Succeeded";
|
|
62
|
-
PullRequestAsyncStatus$1[PullRequestAsyncStatus$1["RejectedByPolicy"] = 4] = "RejectedByPolicy";
|
|
63
|
-
PullRequestAsyncStatus$1[PullRequestAsyncStatus$1["Failure"] = 5] = "Failure";
|
|
64
|
-
return PullRequestAsyncStatus$1;
|
|
65
|
-
}({});
|
|
66
|
-
let PullRequestStatus = /* @__PURE__ */ function(PullRequestStatus$1) {
|
|
67
|
-
PullRequestStatus$1[PullRequestStatus$1["NotSet"] = 0] = "NotSet";
|
|
68
|
-
PullRequestStatus$1[PullRequestStatus$1["Active"] = 1] = "Active";
|
|
69
|
-
PullRequestStatus$1[PullRequestStatus$1["Abandoned"] = 2] = "Abandoned";
|
|
70
|
-
PullRequestStatus$1[PullRequestStatus$1["Completed"] = 3] = "Completed";
|
|
71
|
-
PullRequestStatus$1[PullRequestStatus$1["All"] = 4] = "All";
|
|
72
|
-
return PullRequestStatus$1;
|
|
73
|
-
}({});
|
|
74
|
-
|
|
75
|
-
//#endregion
|
|
76
|
-
//#region src/azure/models.ts
|
|
10
|
+
//#region src/azure/client/constants.ts
|
|
11
|
+
const API_VERSION = "5.0";
|
|
12
|
+
const API_VERSION_PREVIEW = "5.0-preview";
|
|
13
|
+
/** Returned when no user is authenticated */
|
|
14
|
+
const ANONYMOUS_USER_ID = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa";
|
|
77
15
|
/**
|
|
78
16
|
* Pull request property names used to store metadata about the pull request.
|
|
79
17
|
* https://learn.microsoft.com/en-us/rest/api/azure/devops/git/pull-request-properties
|
|
80
18
|
*/
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
19
|
+
const PR_PROPERTY_MICROSOFT_GIT_SOURCE_REF_NAME = "Microsoft.Git.PullRequest.SourceRefName";
|
|
20
|
+
const PR_PROPERTY_DEPENDABOT_PACKAGE_MANAGER = "Dependabot.PackageManager";
|
|
21
|
+
const PR_PROPERTY_DEPENDABOT_DEPENDENCIES = "Dependabot.Dependencies";
|
|
22
|
+
const PR_DESCRIPTION_MAX_LENGTH = 4e3;
|
|
84
23
|
|
|
85
24
|
//#endregion
|
|
86
|
-
//#region src/azure/
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
25
|
+
//#region src/azure/client/client-base.ts
|
|
26
|
+
var BaseAzureDevOpsClient = class {
|
|
27
|
+
constructor(client) {
|
|
28
|
+
this.client = client;
|
|
29
|
+
}
|
|
30
|
+
makeUrl(path$1, params, apiVersion = API_VERSION) {
|
|
31
|
+
if (typeof params === "string") {
|
|
32
|
+
apiVersion = params;
|
|
33
|
+
params = {};
|
|
34
|
+
}
|
|
35
|
+
return `${path$1}?${Object.entries({
|
|
36
|
+
"api-version": apiVersion,
|
|
37
|
+
...params
|
|
38
|
+
}).filter(([, value]) => value).map(([key, value]) => `${key}=${value}`).join("&")}`;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/azure/client/client-connection.ts
|
|
44
|
+
var ConnectionClient = class extends BaseAzureDevOpsClient {
|
|
45
|
+
/**
|
|
46
|
+
* Get the connection data for the current user.
|
|
47
|
+
*/
|
|
48
|
+
async get() {
|
|
49
|
+
return await this.client.get(this.makeUrl("_apis/connectiondata", API_VERSION_PREVIEW)).json();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region src/azure/client/client-git.ts
|
|
55
|
+
var GitClient = class extends BaseAzureDevOpsClient {
|
|
56
|
+
async getItem(projectIdOrName, repositoryIdOrName, path$1, includeContent = true, latestProcessedChange = true) {
|
|
57
|
+
try {
|
|
58
|
+
return await this.client.get(this.makeUrl(`${encodeURIComponent(projectIdOrName)}/_apis/git/repositories/${encodeURIComponent(repositoryIdOrName)}/items`, {
|
|
59
|
+
path: path$1,
|
|
60
|
+
includeContent,
|
|
61
|
+
latestProcessedChange
|
|
62
|
+
})).json();
|
|
63
|
+
} catch (e) {
|
|
64
|
+
if (isHTTPError(e) && e.response.status === 404) return;
|
|
65
|
+
throw e;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async getPush(projectIdOrName, repositoryIdOrName, pushId, includeCommits, includeRefUpdates) {
|
|
69
|
+
return await this.client.get(this.makeUrl(`${encodeURIComponent(projectIdOrName)}/_apis/git/repositories/${encodeURIComponent(repositoryIdOrName)}/pushes/${pushId}`, {
|
|
70
|
+
includeCommits,
|
|
71
|
+
includeRefUpdates
|
|
72
|
+
})).json();
|
|
73
|
+
}
|
|
74
|
+
async createPush(projectIdOrName, repositoryIdOrName, push) {
|
|
75
|
+
return await this.client.post(this.makeUrl(`${encodeURIComponent(projectIdOrName)}/_apis/git/repositories/${encodeURIComponent(repositoryIdOrName)}/pushes`), { json: push }).json();
|
|
76
|
+
}
|
|
77
|
+
async getDiffCommits(projectIdOrName, repositoryIdOrName, baseVersion, targetVersion) {
|
|
78
|
+
return await this.client.get(this.makeUrl(`${encodeURIComponent(projectIdOrName)}/_apis/git/repositories/${encodeURIComponent(repositoryIdOrName)}/diffs/commits`, {
|
|
79
|
+
baseVersion,
|
|
80
|
+
baseVersionType: "commit",
|
|
81
|
+
targetVersion,
|
|
82
|
+
targetVersionType: "commit"
|
|
83
|
+
})).json();
|
|
84
|
+
}
|
|
85
|
+
async updateRef(projectIdOrName, repositoryIdOrName, ref) {
|
|
86
|
+
return (await this.client.post(this.makeUrl(`${encodeURIComponent(projectIdOrName)}/_apis/git/repositories/${encodeURIComponent(repositoryIdOrName)}/refs`), { json: ref }).json()).value;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/azure/client/client-identity.ts
|
|
92
|
+
var IdentityClient = class extends BaseAzureDevOpsClient {
|
|
93
|
+
/**
|
|
94
|
+
* Get the identities that match the given user name, email, or group name.
|
|
95
|
+
* Requires scope "Identity (Read)" (vso.identity).
|
|
96
|
+
* @param filterValue username, email, or group name
|
|
97
|
+
* @returns
|
|
98
|
+
*/
|
|
99
|
+
async get(filterValue) {
|
|
100
|
+
return (await this.client.get(this.makeUrl("_apis/identities", {
|
|
101
|
+
searchFilter: "General",
|
|
102
|
+
filterValue,
|
|
103
|
+
queryMembership: "None"
|
|
104
|
+
})).json())?.value;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/azure/client/client-projects.ts
|
|
110
|
+
var ProjectsClient = class extends BaseAzureDevOpsClient {
|
|
111
|
+
async list() {
|
|
112
|
+
return (await this.client.get(this.makeUrl("_apis/projects")).json())?.value;
|
|
113
|
+
}
|
|
114
|
+
async get(idOrName) {
|
|
115
|
+
return await this.client.get(this.makeUrl(`_apis/projects/${encodeURIComponent(idOrName)}`)).json();
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
//#endregion
|
|
120
|
+
//#region src/azure/client/client-pull-requests.ts
|
|
121
|
+
var PullRequestsClient = class extends BaseAzureDevOpsClient {
|
|
122
|
+
/**
|
|
123
|
+
* List pull requests
|
|
124
|
+
* Requires scope "Code (Read)" (vso.code).
|
|
125
|
+
* @param projectIdOrName
|
|
126
|
+
* @param repositoryIdOrName
|
|
127
|
+
* @param creatorId ID of the user who created the pull requests
|
|
128
|
+
* @param status The status of the pull requests to filter by
|
|
129
|
+
*/
|
|
130
|
+
async list(projectIdOrName, repositoryIdOrName, creatorId, status) {
|
|
131
|
+
return (await this.client.get(this.makeUrl(`${projectIdOrName}/_apis/git/repositories/${repositoryIdOrName}/pullrequests`, {
|
|
132
|
+
"searchCriteria.creatorId": creatorId,
|
|
133
|
+
"searchCriteria.status": status
|
|
134
|
+
})).json())?.value;
|
|
135
|
+
}
|
|
136
|
+
async get(projectIdOrName, repositoryIdOrName, pullRequestId) {
|
|
137
|
+
return await this.client.get(this.makeUrl(`${projectIdOrName}/_apis/git/repositories/${repositoryIdOrName}/pullrequests/${pullRequestId}`)).json();
|
|
138
|
+
}
|
|
139
|
+
async create(projectIdOrName, repositoryIdOrName, pr) {
|
|
140
|
+
return await this.client.post(this.makeUrl(`${projectIdOrName}/_apis/git/repositories/${repositoryIdOrName}/pullrequests`), { json: pr }).json();
|
|
141
|
+
}
|
|
142
|
+
async update(projectIdOrName, repositoryIdOrName, pullRequestId, pr) {
|
|
143
|
+
return await this.client.patch(this.makeUrl(`${projectIdOrName}/_apis/git/repositories/${repositoryIdOrName}/pullrequests/${pullRequestId}`), { json: pr }).json();
|
|
144
|
+
}
|
|
145
|
+
async getProperties(projectIdOrName, repositoryIdOrName, pullRequestId) {
|
|
146
|
+
const response = await this.client.get(this.makeUrl(`${projectIdOrName}/_apis/git/repositories/${repositoryIdOrName}/pullrequests/${pullRequestId}/properties`)).json();
|
|
147
|
+
return Object.entries(response?.value || {}).filter(([, val]) => val?.$value).map(([key, val]) => ({
|
|
148
|
+
name: key,
|
|
149
|
+
value: val.$value
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
152
|
+
async setProperties(projectIdOrName, repositoryIdOrName, pullRequestId, properties) {
|
|
153
|
+
return await this.client.patch(this.makeUrl(`${projectIdOrName}/_apis/git/repositories/${repositoryIdOrName}/pullrequests/${pullRequestId}/properties`), {
|
|
154
|
+
headers: { "Content-Type": "application/json-patch+json" },
|
|
155
|
+
json: properties.map((property) => {
|
|
156
|
+
return {
|
|
157
|
+
op: "add",
|
|
158
|
+
path: `/${property.name}`,
|
|
159
|
+
value: property.value
|
|
160
|
+
};
|
|
161
|
+
})
|
|
162
|
+
}).json();
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Approve a pull request.
|
|
166
|
+
* Requires scope "Code (Write)" (vso.code_write).
|
|
167
|
+
*/
|
|
168
|
+
async approve(projectIdOrName, repositoryIdOrName, pullRequestId, userId) {
|
|
169
|
+
return await this.client.put(this.makeUrl(`${projectIdOrName}/_apis/git/repositories/${repositoryIdOrName}/pullrequests/${pullRequestId}/reviewers/${userId}`, "7.1"), { json: {
|
|
170
|
+
vote: 10,
|
|
171
|
+
isReapprove: true
|
|
172
|
+
} }).json();
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Abandon a pull request.
|
|
176
|
+
* Requires scope "Code (Write)" (vso.code_write).
|
|
177
|
+
*/
|
|
178
|
+
async abandon(projectIdOrName, repositoryIdOrName, pullRequestId, userId) {
|
|
179
|
+
return await this.client.patch(this.makeUrl(`${projectIdOrName}/_apis/git/repositories/${repositoryIdOrName}/pullrequests/${pullRequestId}`), { json: {
|
|
180
|
+
status: "abandoned",
|
|
181
|
+
closedBy: { id: userId }
|
|
182
|
+
} }).json();
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Get commits of a pull request.
|
|
186
|
+
* Requires scope "Code (Read)" (vso.code_read).
|
|
187
|
+
*/
|
|
188
|
+
async getCommits(projectIdOrName, repositoryIdOrName, pullRequestId) {
|
|
189
|
+
return (await this.client.get(this.makeUrl(`${projectIdOrName}/_apis/git/repositories/${repositoryIdOrName}/pullrequests/${pullRequestId}/commits`)).json())?.value;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Create a comment thread on a pull request.
|
|
193
|
+
* Requires scope "Code (Write)" (vso.code_write).
|
|
194
|
+
*/
|
|
195
|
+
async createCommentThread(projectIdOrName, repositoryIdOrName, pullRequestId, thread) {
|
|
196
|
+
return await this.client.post(this.makeUrl(`${projectIdOrName}/_apis/git/repositories/${repositoryIdOrName}/pullrequests/${pullRequestId}/threads`), { json: thread }).json();
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
//#endregion
|
|
201
|
+
//#region src/azure/client/client-repositories.ts
|
|
202
|
+
var RepositoriesClient = class extends BaseAzureDevOpsClient {
|
|
203
|
+
async list(projectIdOrName) {
|
|
204
|
+
return (await this.client.get(this.makeUrl(`${encodeURIComponent(projectIdOrName)}/_apis/git/repositories`)).json())?.value;
|
|
205
|
+
}
|
|
206
|
+
async get(projectIdOrName, repositoryIdOrName) {
|
|
207
|
+
try {
|
|
208
|
+
return await this.client.get(this.makeUrl(`${encodeURIComponent(projectIdOrName)}/_apis/git/repositories/${encodeURIComponent(repositoryIdOrName)}`)).json();
|
|
209
|
+
} catch (e) {
|
|
210
|
+
if (isHTTPError(e) && e.response.status === 404) return;
|
|
211
|
+
throw e;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Get the list of refs (a.k.a branch names) for a repository.
|
|
216
|
+
* Requires scope "Code (Read)" (vso.code).
|
|
217
|
+
* @param projectIdOrName
|
|
218
|
+
* @param repositoryIdOrName
|
|
219
|
+
* @returns
|
|
220
|
+
*/
|
|
221
|
+
async getRefs(projectIdOrName, repositoryIdOrName) {
|
|
222
|
+
return (await this.client.get(this.makeUrl(`${projectIdOrName}/_apis/git/repositories/${repositoryIdOrName}/refs`)).json())?.value;
|
|
223
|
+
}
|
|
224
|
+
async getBranchStats(projectIdOrName, repositoryIdOrName, branchName) {
|
|
225
|
+
return await this.client.get(this.makeUrl(`${projectIdOrName}/_apis/git/repositories/${repositoryIdOrName}/stats/branches`, { name: branchName })).json();
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
//#endregion
|
|
230
|
+
//#region src/azure/client/client-subscriptions.ts
|
|
231
|
+
var HookSubscriptionsClient = class extends BaseAzureDevOpsClient {
|
|
232
|
+
async query(query) {
|
|
233
|
+
return (await this.client.post(this.makeUrl("_apis/hooks/subscriptionsquery"), { json: query }).json())?.results;
|
|
234
|
+
}
|
|
235
|
+
async create(subscription) {
|
|
236
|
+
return await this.client.post(this.makeUrl("_apis/hooks/subscriptions"), { json: subscription }).json();
|
|
237
|
+
}
|
|
238
|
+
async replace(subscriptionId, subscription) {
|
|
239
|
+
return await this.client.put(this.makeUrl(`_apis/hooks/subscriptions/${subscriptionId}`), { json: subscription }).json();
|
|
240
|
+
}
|
|
241
|
+
async delete(subscriptionId) {
|
|
242
|
+
await this.client.delete(this.makeUrl(`_apis/hooks/subscriptions/${subscriptionId}`)).json();
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
//#endregion
|
|
247
|
+
//#region src/azure/client/client.ts
|
|
248
|
+
var AzureDevOpsClient = class AzureDevOpsClient {
|
|
249
|
+
organizationSlug;
|
|
250
|
+
organizationUrl;
|
|
251
|
+
connection;
|
|
252
|
+
identity;
|
|
253
|
+
projects;
|
|
254
|
+
repositories;
|
|
255
|
+
git;
|
|
256
|
+
pullRequests;
|
|
257
|
+
subscriptions;
|
|
258
|
+
constructor(url, accessToken, debug = false) {
|
|
259
|
+
this.organizationSlug = url.organisation;
|
|
260
|
+
const organizationUrl = url.value.toString().replace(/\/$/, "");
|
|
261
|
+
this.organizationUrl = organizationUrl;
|
|
262
|
+
const mainClientOptions = AzureDevOpsClient.createClientOptions(accessToken, debug, { prefixUrl: organizationUrl });
|
|
263
|
+
const mainClient = ky.create(mainClientOptions);
|
|
264
|
+
this.connection = new ConnectionClient(mainClient);
|
|
265
|
+
this.projects = new ProjectsClient(mainClient);
|
|
266
|
+
this.repositories = new RepositoriesClient(mainClient);
|
|
267
|
+
this.git = new GitClient(mainClient);
|
|
268
|
+
this.pullRequests = new PullRequestsClient(mainClient);
|
|
269
|
+
this.subscriptions = new HookSubscriptionsClient(mainClient);
|
|
270
|
+
const identityApiUrl = url["identity-api-url"].toString().replace(/\/$/, "");
|
|
271
|
+
this.identity = new IdentityClient(ky.create({
|
|
272
|
+
...mainClientOptions,
|
|
273
|
+
prefixUrl: identityApiUrl
|
|
274
|
+
}));
|
|
275
|
+
}
|
|
276
|
+
static createClientOptions(accessToken, debug, options) {
|
|
277
|
+
return {
|
|
278
|
+
headers: {
|
|
279
|
+
Authorization: `Basic ${Buffer.from(`:${accessToken}`).toString("base64")}`,
|
|
280
|
+
Accept: "application/json"
|
|
281
|
+
},
|
|
282
|
+
hooks: {
|
|
283
|
+
beforeRequest: [async (request, options$1) => {
|
|
284
|
+
if (debug) logger.debug(`🌎 🠊 [${request.method}] ${request.url}`);
|
|
285
|
+
}],
|
|
286
|
+
afterResponse: [async (request, options$1, response) => {
|
|
287
|
+
if (debug) {
|
|
288
|
+
logger.debug(`🌎 🠈 [${response.status}] ${response.statusText}`);
|
|
289
|
+
if (request.body) logger.debug(`REQUEST: ${JSON.stringify(request.body)}`);
|
|
290
|
+
}
|
|
291
|
+
}],
|
|
292
|
+
beforeRetry: [async ({ request, options: options$1, error, retryCount }) => {
|
|
293
|
+
if (debug && isHTTPError(error)) logger.debug(`⏳ Retrying failed request with status code: ${error.response.status}`);
|
|
294
|
+
}]
|
|
295
|
+
},
|
|
296
|
+
retry: {
|
|
297
|
+
limit: 3,
|
|
298
|
+
delay: (attempt) => 3e3
|
|
299
|
+
},
|
|
300
|
+
...options
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
//#endregion
|
|
306
|
+
//#region src/azure/client/types.ts
|
|
307
|
+
const AzdoVersionControlChangeTypeSchema = z.enum([
|
|
308
|
+
"none",
|
|
309
|
+
"add",
|
|
310
|
+
"edit",
|
|
311
|
+
"encoding",
|
|
312
|
+
"rename",
|
|
313
|
+
"delete",
|
|
314
|
+
"undelete",
|
|
315
|
+
"branch",
|
|
316
|
+
"merge",
|
|
317
|
+
"lock",
|
|
318
|
+
"rollback",
|
|
319
|
+
"sourceRename",
|
|
320
|
+
"targetRename",
|
|
321
|
+
"property",
|
|
322
|
+
"all"
|
|
323
|
+
]);
|
|
324
|
+
const AZDO_PULL_REQUEST_MERGE_STRATEGIES = [
|
|
325
|
+
"noFastForward",
|
|
326
|
+
"squash",
|
|
327
|
+
"rebase",
|
|
328
|
+
"rebaseMerge"
|
|
329
|
+
];
|
|
330
|
+
const AzdoPullRequestMergeStrategySchema = z.enum(AZDO_PULL_REQUEST_MERGE_STRATEGIES);
|
|
331
|
+
const AzdoCommentThreadStatusSchema = z.enum([
|
|
332
|
+
"unknown",
|
|
333
|
+
"active",
|
|
334
|
+
"fixed",
|
|
335
|
+
"wontFix",
|
|
336
|
+
"closed",
|
|
337
|
+
"byDesign",
|
|
338
|
+
"pending"
|
|
339
|
+
]);
|
|
340
|
+
const AzdoCommentTypeSchema = z.enum([
|
|
341
|
+
"unknown",
|
|
342
|
+
"text",
|
|
343
|
+
"codeChange",
|
|
344
|
+
"system"
|
|
345
|
+
]);
|
|
346
|
+
const AzdoPullRequestAsyncStatusSchema = z.enum([
|
|
347
|
+
"notSet",
|
|
348
|
+
"queued",
|
|
349
|
+
"conflicts",
|
|
350
|
+
"succeeded",
|
|
351
|
+
"rejectedByPolicy",
|
|
352
|
+
"failure"
|
|
353
|
+
]);
|
|
354
|
+
const AzdoPullRequestStatusSchema = z.enum([
|
|
355
|
+
"notSet",
|
|
356
|
+
"active",
|
|
357
|
+
"abandoned",
|
|
358
|
+
"completed",
|
|
359
|
+
"all"
|
|
360
|
+
]);
|
|
361
|
+
const AzdoProjectSchema = z.object({
|
|
362
|
+
id: z.string(),
|
|
363
|
+
name: z.string(),
|
|
364
|
+
description: z.string().optional(),
|
|
365
|
+
url: z.string(),
|
|
366
|
+
state: z.enum([
|
|
367
|
+
"deleting",
|
|
368
|
+
"new",
|
|
369
|
+
"wellFormed",
|
|
370
|
+
"createPending",
|
|
371
|
+
"all",
|
|
372
|
+
"unchanged",
|
|
373
|
+
"deleted"
|
|
374
|
+
]),
|
|
375
|
+
_links: z.object({
|
|
376
|
+
self: z.object({ href: z.string() }),
|
|
377
|
+
collection: z.object({ href: z.string() }),
|
|
378
|
+
web: z.object({ href: z.string() })
|
|
379
|
+
}).optional()
|
|
380
|
+
});
|
|
381
|
+
const AzdoRepositorySchema = z.object({
|
|
382
|
+
id: z.string(),
|
|
383
|
+
name: z.string(),
|
|
384
|
+
defaultBranch: z.string().optional(),
|
|
385
|
+
project: AzdoProjectSchema,
|
|
386
|
+
isDisabled: z.boolean().optional(),
|
|
387
|
+
isFork: z.boolean().optional(),
|
|
388
|
+
url: z.string(),
|
|
389
|
+
remoteUrl: z.string(),
|
|
390
|
+
webUrl: z.string()
|
|
391
|
+
});
|
|
392
|
+
const AzdoIdentitySchema = z.object({
|
|
393
|
+
id: z.string(),
|
|
394
|
+
displayName: z.string(),
|
|
395
|
+
url: z.string()
|
|
396
|
+
});
|
|
397
|
+
const AzdoIdentityRefSchema = z.object({
|
|
398
|
+
id: z.string().optional(),
|
|
399
|
+
displayName: z.string().optional(),
|
|
400
|
+
uniqueName: z.string().optional(),
|
|
401
|
+
url: z.string().optional()
|
|
402
|
+
});
|
|
403
|
+
const AzdoConnectionDataSchema = z.object({
|
|
404
|
+
authenticatedUser: AzdoIdentitySchema,
|
|
405
|
+
authorizedUser: AzdoIdentitySchema
|
|
406
|
+
});
|
|
407
|
+
const AzdoGitUserDateSchema = z.object({
|
|
408
|
+
name: z.string(),
|
|
409
|
+
email: z.string(),
|
|
410
|
+
date: z.string().optional()
|
|
411
|
+
});
|
|
412
|
+
const AzdoGitRefSchema = z.object({
|
|
413
|
+
name: z.string(),
|
|
414
|
+
objectId: z.string(),
|
|
415
|
+
isLocked: z.boolean().optional()
|
|
416
|
+
});
|
|
417
|
+
const AzdoGitRefUpdateResultSchema = AzdoGitRefSchema.extend({
|
|
418
|
+
oldObjectId: z.string(),
|
|
419
|
+
newObjectId: z.string(),
|
|
420
|
+
success: z.boolean(),
|
|
421
|
+
customMessage: z.string().optional()
|
|
422
|
+
});
|
|
423
|
+
const AzdoGitChangeSchema = z.object({
|
|
424
|
+
changeType: AzdoVersionControlChangeTypeSchema,
|
|
425
|
+
item: z.object({ path: z.string() }).optional(),
|
|
426
|
+
newContent: z.object({
|
|
427
|
+
content: z.string(),
|
|
428
|
+
contentType: z.enum(["rawtext", "base64encoded"])
|
|
429
|
+
}).optional(),
|
|
430
|
+
originalPath: z.string().optional()
|
|
431
|
+
});
|
|
432
|
+
const AzdoGitCommitRefSchema = z.object({
|
|
433
|
+
commitId: z.string(),
|
|
434
|
+
author: AzdoGitUserDateSchema.optional(),
|
|
435
|
+
committer: AzdoGitUserDateSchema.optional(),
|
|
436
|
+
changes: AzdoGitChangeSchema.array().optional()
|
|
437
|
+
});
|
|
438
|
+
const AzdoGitPushSchema = z.object({
|
|
439
|
+
commits: AzdoGitCommitRefSchema.array(),
|
|
440
|
+
refUpdates: AzdoGitRefSchema.array()
|
|
441
|
+
});
|
|
442
|
+
const AzdoGitRefUpdateSchema = z.object({
|
|
443
|
+
name: z.string(),
|
|
444
|
+
oldObjectId: z.string(),
|
|
445
|
+
newObjectId: z.string().optional(),
|
|
446
|
+
isLocked: z.boolean().optional()
|
|
447
|
+
});
|
|
448
|
+
const AzdoGitPushCreateSchema = z.object({
|
|
449
|
+
refUpdates: AzdoGitRefUpdateSchema.array(),
|
|
450
|
+
commits: z.object({
|
|
451
|
+
comment: z.string(),
|
|
452
|
+
author: AzdoGitUserDateSchema.optional(),
|
|
453
|
+
changes: AzdoGitChangeSchema.array()
|
|
454
|
+
}).array()
|
|
455
|
+
});
|
|
456
|
+
const AzdoGitBranchStatsSchema = z.object({
|
|
457
|
+
aheadCount: z.number(),
|
|
458
|
+
behindCount: z.number()
|
|
459
|
+
});
|
|
460
|
+
const AzdoGitCommitDiffsSchema = z.object({
|
|
461
|
+
allChangesIncluded: z.boolean(),
|
|
462
|
+
baseCommit: z.string(),
|
|
463
|
+
changes: AzdoGitChangeSchema.array(),
|
|
464
|
+
targetCommit: z.string()
|
|
465
|
+
});
|
|
466
|
+
const AzdoRepositoryItemSchema = z.object({
|
|
467
|
+
latestProcessedChange: AzdoGitCommitRefSchema.optional(),
|
|
468
|
+
content: z.string().optional()
|
|
469
|
+
});
|
|
470
|
+
const AzdoIdentityRefWithVoteSchema = z.object({
|
|
471
|
+
id: z.string().optional(),
|
|
472
|
+
displayName: z.string().optional(),
|
|
473
|
+
vote: z.number().optional(),
|
|
474
|
+
hasDeclined: z.boolean().optional(),
|
|
475
|
+
isFlagged: z.boolean().optional(),
|
|
476
|
+
isRequired: z.boolean().optional()
|
|
477
|
+
});
|
|
478
|
+
const AzdoPullRequestSchema = z.object({
|
|
479
|
+
pullRequestId: z.number(),
|
|
480
|
+
status: AzdoPullRequestStatusSchema,
|
|
481
|
+
isDraft: z.boolean(),
|
|
482
|
+
sourceRefName: z.string(),
|
|
483
|
+
targetRefName: z.string(),
|
|
484
|
+
title: z.string(),
|
|
485
|
+
description: z.string().optional(),
|
|
486
|
+
lastMergeCommit: AzdoGitCommitRefSchema,
|
|
487
|
+
lastMergeSourceCommit: AzdoGitCommitRefSchema,
|
|
488
|
+
mergeStatus: AzdoPullRequestAsyncStatusSchema,
|
|
489
|
+
reviewers: AzdoIdentityRefWithVoteSchema.array().optional(),
|
|
490
|
+
workItemRefs: z.object({ id: z.string() }).array().optional(),
|
|
491
|
+
labels: z.object({ name: z.string() }).array().optional(),
|
|
492
|
+
autoCompleteSetBy: AzdoIdentityRefSchema.optional(),
|
|
493
|
+
completionOptions: z.object({
|
|
494
|
+
autoCompleteIgnoreConfigIds: z.number().array().optional(),
|
|
495
|
+
deleteSourceBranch: z.boolean().optional(),
|
|
496
|
+
mergeCommitMessage: z.string().optional(),
|
|
497
|
+
mergeStrategy: AzdoPullRequestMergeStrategySchema.optional(),
|
|
498
|
+
transitionWorkItems: z.boolean().optional()
|
|
499
|
+
}).optional(),
|
|
500
|
+
closedBy: AzdoIdentityRefSchema.optional()
|
|
501
|
+
});
|
|
502
|
+
const AzdoPropertiesSchema = z.record(z.string(), z.object({
|
|
503
|
+
$type: z.string(),
|
|
504
|
+
$value: z.string()
|
|
505
|
+
}));
|
|
506
|
+
const AzdoPullRequestCommentSchema = z.object({
|
|
507
|
+
id: z.number().optional(),
|
|
508
|
+
parentCommentId: z.number().optional(),
|
|
509
|
+
content: z.string(),
|
|
510
|
+
commentType: AzdoCommentTypeSchema,
|
|
511
|
+
publishedDate: z.string().optional(),
|
|
512
|
+
author: AzdoIdentityRefSchema
|
|
513
|
+
});
|
|
514
|
+
const AzdoPullRequestCommentThreadSchema = z.object({
|
|
515
|
+
id: z.number(),
|
|
516
|
+
comments: AzdoPullRequestCommentSchema.array(),
|
|
517
|
+
status: AzdoCommentThreadStatusSchema
|
|
518
|
+
});
|
|
519
|
+
const AzdoSubscriptionSchema = z.object({
|
|
520
|
+
id: z.string(),
|
|
521
|
+
status: z.enum([
|
|
522
|
+
"enabled",
|
|
523
|
+
"onProbation",
|
|
524
|
+
"disabledByUser",
|
|
525
|
+
"disabledBySystem",
|
|
526
|
+
"disabledByInactiveIdentity"
|
|
527
|
+
]),
|
|
528
|
+
publisherId: z.string(),
|
|
529
|
+
publisherInputs: z.record(z.string(), z.string()),
|
|
530
|
+
consumerId: z.string().optional(),
|
|
531
|
+
consumerActionId: z.string().optional(),
|
|
532
|
+
consumerInputs: z.record(z.string(), z.string()),
|
|
533
|
+
eventType: z.string(),
|
|
534
|
+
resourceVersion: z.string(),
|
|
535
|
+
eventDescription: z.string().optional(),
|
|
536
|
+
actionDescription: z.string().optional()
|
|
537
|
+
});
|
|
538
|
+
const AzdoSubscriptionsQueryResponseSchema = z.object({ results: AzdoSubscriptionSchema.array() });
|
|
539
|
+
const AzdoSubscriptionsQueryInputFilterSchema = z.object({ conditions: z.object({
|
|
540
|
+
caseSensitive: z.boolean().optional(),
|
|
541
|
+
inputId: z.string().optional(),
|
|
542
|
+
inputValue: z.string().optional(),
|
|
543
|
+
operator: z.enum(["equals", "notEquals"])
|
|
544
|
+
}).array().optional() });
|
|
545
|
+
const AzdoSubscriptionsQuerySchema = z.object({
|
|
546
|
+
consumerActionId: z.string().optional(),
|
|
547
|
+
consumerId: z.string().optional(),
|
|
548
|
+
consumerInputFilters: AzdoSubscriptionsQueryInputFilterSchema.array().optional(),
|
|
549
|
+
eventType: z.string().optional(),
|
|
550
|
+
publisherId: z.string().optional(),
|
|
551
|
+
publisherInputFilters: AzdoSubscriptionsQueryInputFilterSchema.array().optional(),
|
|
552
|
+
subscriberId: z.string().optional()
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
//#endregion
|
|
556
|
+
//#region src/azure/client/utils.ts
|
|
94
557
|
function buildPullRequestProperties(packageManager, dependencies) {
|
|
95
558
|
return [{
|
|
96
|
-
name:
|
|
559
|
+
name: PR_PROPERTY_DEPENDABOT_PACKAGE_MANAGER,
|
|
97
560
|
value: packageManager
|
|
98
561
|
}, {
|
|
99
|
-
name:
|
|
562
|
+
name: PR_PROPERTY_DEPENDABOT_DEPENDENCIES,
|
|
100
563
|
value: JSON.stringify(dependencies)
|
|
101
564
|
}];
|
|
102
565
|
}
|
|
103
566
|
function parsePullRequestProperties(pullRequests, packageManager) {
|
|
104
567
|
return Object.fromEntries(pullRequests.filter((pr) => {
|
|
105
|
-
return pr.properties?.find((p) => p.name ===
|
|
568
|
+
return pr.properties?.find((p) => p.name === PR_PROPERTY_DEPENDABOT_PACKAGE_MANAGER && (packageManager === null || p.value === packageManager));
|
|
106
569
|
}).map((pr) => {
|
|
107
|
-
return [pr.
|
|
570
|
+
return [pr.pullRequestId, DependabotPersistedPrSchema.parse(JSON.parse(pr.properties.find((p) => p.name === PR_PROPERTY_DEPENDABOT_DEPENDENCIES).value))];
|
|
108
571
|
}));
|
|
109
572
|
}
|
|
110
573
|
function getPullRequestForDependencyNames(existingPullRequests, packageManager, dependencyNames) {
|
|
111
574
|
return existingPullRequests.find((pr) => {
|
|
112
|
-
return pr.properties?.find((p) => p.name ===
|
|
575
|
+
return pr.properties?.find((p) => p.name === PR_PROPERTY_DEPENDABOT_PACKAGE_MANAGER && p.value === packageManager) && pr.properties?.find((p) => p.name === PR_PROPERTY_DEPENDABOT_DEPENDENCIES && areEqual(getDependencyNames(DependabotPersistedPrSchema.parse(JSON.parse(p.value))), dependencyNames));
|
|
113
576
|
});
|
|
114
577
|
}
|
|
115
|
-
function
|
|
116
|
-
return (Array.isArray(dependencies) ? dependencies : dependencies.dependencies).map((dep) => dep["dependency-name"]?.toString());
|
|
117
|
-
}
|
|
118
|
-
function areEqual(a, b) {
|
|
119
|
-
if (a.length !== b.length) return false;
|
|
120
|
-
return a.every((name) => b.includes(name));
|
|
121
|
-
}
|
|
122
|
-
function getPullRequestChangedFilesForOutputData(data) {
|
|
578
|
+
function getPullRequestChangedFiles(data) {
|
|
123
579
|
return data["updated-dependency-files"].filter((file) => file.type === "file").map((file) => {
|
|
124
|
-
let changeType =
|
|
125
|
-
if (file.deleted === true || file.operation === "delete") changeType =
|
|
126
|
-
else if (file.operation === "update") changeType =
|
|
127
|
-
else changeType =
|
|
580
|
+
let changeType = "none";
|
|
581
|
+
if (file.deleted === true || file.operation === "delete") changeType = "delete";
|
|
582
|
+
else if (file.operation === "update") changeType = "edit";
|
|
583
|
+
else changeType = "add";
|
|
128
584
|
return {
|
|
129
585
|
changeType,
|
|
130
586
|
path: path.join(file.directory, file.name),
|
|
@@ -133,230 +589,91 @@ function getPullRequestChangedFilesForOutputData(data) {
|
|
|
133
589
|
};
|
|
134
590
|
});
|
|
135
591
|
}
|
|
136
|
-
function getPullRequestCloseReasonForOutputData(data) {
|
|
137
|
-
const leadDependencyName = data["dependency-names"][0];
|
|
138
|
-
let reason;
|
|
139
|
-
switch (data.reason) {
|
|
140
|
-
case "dependencies_changed":
|
|
141
|
-
reason = `Looks like the dependencies have changed`;
|
|
142
|
-
break;
|
|
143
|
-
case "dependency_group_empty":
|
|
144
|
-
reason = `Looks like the dependencies in this group are now empty`;
|
|
145
|
-
break;
|
|
146
|
-
case "dependency_removed":
|
|
147
|
-
reason = `Looks like ${leadDependencyName} is no longer a dependency`;
|
|
148
|
-
break;
|
|
149
|
-
case "up_to_date":
|
|
150
|
-
reason = `Looks like ${leadDependencyName} is up-to-date now`;
|
|
151
|
-
break;
|
|
152
|
-
case "update_no_longer_possible":
|
|
153
|
-
reason = `Looks like ${leadDependencyName} can no longer be updated`;
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
156
|
-
if (reason && reason.length > 0) reason += ", so this is no longer needed.";
|
|
157
|
-
return reason;
|
|
158
|
-
}
|
|
159
|
-
function getPullRequestDependenciesPropertyValueForOutputData(data) {
|
|
160
|
-
const dependencies = data.dependencies?.map((dep) => {
|
|
161
|
-
return {
|
|
162
|
-
"dependency-name": dep.name,
|
|
163
|
-
"dependency-version": dep.version,
|
|
164
|
-
directory: dep.directory
|
|
165
|
-
};
|
|
166
|
-
});
|
|
167
|
-
const dependencyGroupName = data["dependency-group"]?.name;
|
|
168
|
-
if (!dependencyGroupName) return dependencies;
|
|
169
|
-
return {
|
|
170
|
-
"dependency-group-name": dependencyGroupName,
|
|
171
|
-
dependencies
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
function getPullRequestDescription(packageManager, body, dependencies) {
|
|
175
|
-
let header = "";
|
|
176
|
-
const footer = "";
|
|
177
|
-
const description = (body || "").replace(new RegExp(decodeURIComponent("%EF%BF%BD%EF%BF%BD%EF%BF%BD"), "g"), "");
|
|
178
|
-
if (dependencies.length === 1) {
|
|
179
|
-
const compatibilityScoreBadges = dependencies.map((dep) => {
|
|
180
|
-
return ``;
|
|
181
|
-
});
|
|
182
|
-
header += `${compatibilityScoreBadges.join(" ")}\n\n`;
|
|
183
|
-
}
|
|
184
|
-
const maxDescriptionLengthAfterHeaderAndFooter = 4e3 - header.length - 0;
|
|
185
|
-
return `${header}${description.substring(0, maxDescriptionLengthAfterHeaderAndFooter)}${footer}`;
|
|
186
|
-
}
|
|
187
592
|
|
|
188
593
|
//#endregion
|
|
189
|
-
//#region src/azure/client.ts
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
/** Azure DevOps REST API client. */
|
|
193
|
-
var AzureDevOpsWebApiClient = class AzureDevOpsWebApiClient {
|
|
194
|
-
organisationApiUrl;
|
|
195
|
-
identityApiUrl;
|
|
196
|
-
accessToken;
|
|
197
|
-
debug;
|
|
594
|
+
//#region src/azure/client/wrapper.ts
|
|
595
|
+
var AzureDevOpsClientWrapper = class {
|
|
596
|
+
inner;
|
|
198
597
|
authenticatedUserId;
|
|
199
|
-
resolvedUserIds;
|
|
200
|
-
|
|
201
|
-
|
|
598
|
+
resolvedUserIds = {};
|
|
599
|
+
/**
|
|
600
|
+
* Create a new Azure DevOps client wrapper.
|
|
601
|
+
* @param url The Azure DevOps organization URL
|
|
602
|
+
* @param accessToken The personal access token for authentication
|
|
603
|
+
* @param debug Enable debug logging for API requests (default: false)
|
|
604
|
+
*/
|
|
202
605
|
constructor(url, accessToken, debug = false) {
|
|
203
|
-
|
|
204
|
-
this.organisationApiUrl = organisationApiUrl.replace(/\/$/, "");
|
|
205
|
-
this.identityApiUrl = getIdentityApiUrl(organisationApiUrl).replace(/\/$/, "");
|
|
206
|
-
this.accessToken = accessToken;
|
|
207
|
-
this.debug = debug;
|
|
208
|
-
this.resolvedUserIds = {};
|
|
606
|
+
this.inner = new AzureDevOpsClient(url, accessToken, debug);
|
|
209
607
|
}
|
|
210
608
|
/**
|
|
211
609
|
* Get the identity of the authenticated user.
|
|
212
|
-
*
|
|
610
|
+
* The result is cached after the first call to avoid repeated API requests.
|
|
213
611
|
*/
|
|
214
612
|
async getUserId() {
|
|
215
613
|
if (!this.authenticatedUserId) {
|
|
216
|
-
this.authenticatedUserId = (await this.
|
|
614
|
+
this.authenticatedUserId = (await this.inner.connection.get())?.authenticatedUser?.id;
|
|
217
615
|
if (!this.authenticatedUserId) throw new Error("Failed to get authenticated user ID");
|
|
218
616
|
}
|
|
219
617
|
return this.authenticatedUserId;
|
|
220
618
|
}
|
|
221
619
|
/**
|
|
222
620
|
* Get the identity id from a user name, email, or group name.
|
|
621
|
+
* Results are cached to avoid repeated API requests for the same identifier.
|
|
622
|
+
*
|
|
223
623
|
* Requires scope "Identity (Read)" (vso.identity).
|
|
224
|
-
* @param
|
|
225
|
-
* @returns
|
|
624
|
+
* @param identifier Username, email, or group name to resolve
|
|
625
|
+
* @returns The resolved identity ID, or undefined if not found or on error
|
|
226
626
|
*/
|
|
227
|
-
async resolveIdentityId(
|
|
228
|
-
if (this.resolvedUserIds[
|
|
627
|
+
async resolveIdentityId(identifier) {
|
|
628
|
+
if (this.resolvedUserIds[identifier]) return this.resolvedUserIds[identifier];
|
|
229
629
|
try {
|
|
230
|
-
const identities = await this.
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
});
|
|
235
|
-
if (!identities?.value || identities.value.length === 0) return;
|
|
236
|
-
this.resolvedUserIds[userNameEmailOrGroupName] = identities.value[0]?.id;
|
|
237
|
-
return this.resolvedUserIds[userNameEmailOrGroupName];
|
|
630
|
+
const identities = await this.inner.identity.get(identifier);
|
|
631
|
+
if (!identities || identities.length === 0) return;
|
|
632
|
+
this.resolvedUserIds[identifier] = identities[0].id;
|
|
633
|
+
return this.resolvedUserIds[identifier];
|
|
238
634
|
} catch (e) {
|
|
239
635
|
logger.error(`Failed to resolve user id: ${e}`);
|
|
240
636
|
logger.debug(e);
|
|
241
637
|
return;
|
|
242
638
|
}
|
|
243
639
|
}
|
|
244
|
-
async getProjects() {
|
|
245
|
-
try {
|
|
246
|
-
return await this.restApiGet(`${this.organisationApiUrl}/_apis/projects`);
|
|
247
|
-
} catch (e) {
|
|
248
|
-
logger.error(`Failed to get projects: ${e}`);
|
|
249
|
-
logger.debug(e);
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
async getProject(idOrName) {
|
|
254
|
-
try {
|
|
255
|
-
return await this.restApiGet(`${this.organisationApiUrl}/_apis/projects/${encodeURIComponent(idOrName)}`);
|
|
256
|
-
} catch (e) {
|
|
257
|
-
logger.error(`Failed to get project: ${e}`);
|
|
258
|
-
logger.debug(e);
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
async getRepositories(projectIdOrName) {
|
|
263
|
-
try {
|
|
264
|
-
return await this.restApiGet(`${this.organisationApiUrl}/${encodeURIComponent(projectIdOrName)}/_apis/git/repositories`);
|
|
265
|
-
} catch (e) {
|
|
266
|
-
logger.error(`Failed to get repositories: ${e}`);
|
|
267
|
-
logger.debug(e);
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
async getRepository(projectIdOrName, repositoryIdOrName) {
|
|
272
|
-
try {
|
|
273
|
-
return await this.restApiGet(`${this.organisationApiUrl}/${encodeURIComponent(projectIdOrName)}/_apis/git/repositories/${encodeURIComponent(repositoryIdOrName)}`);
|
|
274
|
-
} catch (e) {
|
|
275
|
-
if (e instanceof HttpRequestError && e.code === 404) return;
|
|
276
|
-
else {
|
|
277
|
-
logger.error(`Failed to get repository: ${e}`);
|
|
278
|
-
logger.debug(e);
|
|
279
|
-
}
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
async getRepositoryItem(projectIdOrName, repositoryIdOrName, path$1, includeContent = true, latestProcessedChange = true) {
|
|
284
|
-
try {
|
|
285
|
-
return await this.restApiGet(`${this.organisationApiUrl}/${encodeURIComponent(projectIdOrName)}/_apis/git/repositories/${encodeURIComponent(repositoryIdOrName)}/items`, {
|
|
286
|
-
path: path$1,
|
|
287
|
-
includeContent,
|
|
288
|
-
latestProcessedChange
|
|
289
|
-
});
|
|
290
|
-
} catch (e) {
|
|
291
|
-
if (e instanceof HttpRequestError && e.code === 404) return;
|
|
292
|
-
else {
|
|
293
|
-
logger.error(`Failed to get repository item: ${e}`);
|
|
294
|
-
logger.debug(e);
|
|
295
|
-
}
|
|
296
|
-
return;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
640
|
/**
|
|
300
641
|
* Get the default branch for a repository.
|
|
642
|
+
*
|
|
301
643
|
* Requires scope "Code (Read)" (vso.code).
|
|
302
|
-
* @param project
|
|
303
|
-
* @
|
|
304
|
-
* @returns
|
|
644
|
+
* @param options Repository identification options (project and repository)
|
|
645
|
+
* @returns The normalized default branch name (e.g., "main"), or undefined if not found
|
|
305
646
|
*/
|
|
306
|
-
async getDefaultBranch(
|
|
307
|
-
|
|
308
|
-
const repo = await this.restApiGet(`${this.organisationApiUrl}/${project}/_apis/git/repositories/${repository}`);
|
|
309
|
-
if (!repo) throw new Error(`Repository '${project}/${repository}' not found`);
|
|
310
|
-
return normalizeBranchName(repo.defaultBranch);
|
|
311
|
-
} catch (e) {
|
|
312
|
-
logger.error(`Failed to get default branch for '${project}/${repository}': ${e}`);
|
|
313
|
-
logger.debug(e);
|
|
314
|
-
return;
|
|
315
|
-
}
|
|
647
|
+
async getDefaultBranch(options) {
|
|
648
|
+
return normalizeBranchName((await this.inner.repositories.get(options.project, options.repository))?.defaultBranch);
|
|
316
649
|
}
|
|
317
650
|
/**
|
|
318
651
|
* Get the list of branch names for a repository.
|
|
652
|
+
*
|
|
319
653
|
* Requires scope "Code (Read)" (vso.code).
|
|
320
|
-
* @param project
|
|
321
|
-
* @
|
|
322
|
-
* @returns
|
|
654
|
+
* @param options Repository identification options (project and repository)
|
|
655
|
+
* @returns Array of normalized branch names, or undefined if not found
|
|
323
656
|
*/
|
|
324
|
-
async getBranchNames(
|
|
325
|
-
|
|
326
|
-
const refs = await this.restApiGet(`${this.organisationApiUrl}/${project}/_apis/git/repositories/${repository}/refs`);
|
|
327
|
-
if (!refs) throw new Error(`Repository '${project}/${repository}' not found`);
|
|
328
|
-
return refs.value?.map((r) => normalizeBranchName(r.name)) || [];
|
|
329
|
-
} catch (e) {
|
|
330
|
-
logger.error(`Failed to list branch names for '${project}/${repository}': ${e}`);
|
|
331
|
-
logger.debug(e);
|
|
332
|
-
return;
|
|
333
|
-
}
|
|
657
|
+
async getBranchNames(options) {
|
|
658
|
+
return (await this.inner.repositories.getRefs(options.project, options.repository))?.map((r) => normalizeBranchName(r.name));
|
|
334
659
|
}
|
|
335
660
|
/**
|
|
336
|
-
* Get the properties for all active pull
|
|
661
|
+
* Get the properties for all active pull requests created by the specified user.
|
|
662
|
+
* This retrieves both the pull request IDs and their associated properties.
|
|
663
|
+
*
|
|
337
664
|
* Requires scope "Code (Read)" (vso.code).
|
|
338
|
-
* @param
|
|
339
|
-
* @
|
|
340
|
-
* @param creator
|
|
341
|
-
* @returns
|
|
665
|
+
* @param options Repository identification options including the creator user ID
|
|
666
|
+
* @returns Array of pull request IDs with their properties, empty array on error
|
|
342
667
|
*/
|
|
343
|
-
async getActivePullRequestProperties(project, repository,
|
|
668
|
+
async getActivePullRequestProperties({ project, repository, creatorId }) {
|
|
344
669
|
try {
|
|
345
|
-
const pullRequests = await this.
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
if (!pullRequests?.value || pullRequests.value.length === 0) return [];
|
|
350
|
-
return await Promise.all(pullRequests.value.map(async (pr) => {
|
|
351
|
-
const properties = await this.restApiGet(`${this.organisationApiUrl}/${project}/_apis/git/repositories/${repository}/pullrequests/${pr.pullRequestId}/properties`);
|
|
670
|
+
const pullRequests = await this.inner.pullRequests.list(project, repository, creatorId, "active");
|
|
671
|
+
if (!pullRequests || pullRequests.length === 0) return [];
|
|
672
|
+
return await Promise.all(pullRequests.map(async (pr) => {
|
|
673
|
+
const properties = await this.inner.pullRequests.getProperties(project, repository, pr.pullRequestId);
|
|
352
674
|
return {
|
|
353
|
-
|
|
354
|
-
properties
|
|
355
|
-
return {
|
|
356
|
-
name: key,
|
|
357
|
-
value: properties.value[key]?.$value
|
|
358
|
-
};
|
|
359
|
-
}) || []
|
|
675
|
+
pullRequestId: pr.pullRequestId,
|
|
676
|
+
properties
|
|
360
677
|
};
|
|
361
678
|
}));
|
|
362
679
|
} catch (e) {
|
|
@@ -366,38 +683,45 @@ var AzureDevOpsWebApiClient = class AzureDevOpsWebApiClient {
|
|
|
366
683
|
}
|
|
367
684
|
}
|
|
368
685
|
/**
|
|
369
|
-
* Create a new pull request.
|
|
686
|
+
* Create a new pull request with the specified changes.
|
|
687
|
+
* This method performs the following operations:
|
|
688
|
+
* 1. Resolves assignee identities for assignees (if specified)
|
|
689
|
+
* 2. Creates a new branch and pushes changes
|
|
690
|
+
* 3. Creates the pull request with assignees (optional reviewers), labels, and work items
|
|
691
|
+
* 4. Sets pull request properties for dependency metadata
|
|
692
|
+
* 5. Configures auto-complete options (if specified)
|
|
693
|
+
*
|
|
370
694
|
* Requires scope "Code (Write)" (vso.code_write).
|
|
371
695
|
* Requires scope "Identity (Read)" (vso.identity), if assignees are specified.
|
|
372
|
-
* @param
|
|
373
|
-
* @returns
|
|
696
|
+
* @param options Pull request creation options including changes, assignees, and auto-complete settings
|
|
697
|
+
* @returns The created pull request ID, or null on error
|
|
374
698
|
*/
|
|
375
|
-
async createPullRequest(
|
|
376
|
-
logger.info(`Creating pull request '${
|
|
699
|
+
async createPullRequest(options) {
|
|
700
|
+
logger.info(`Creating pull request '${options.title}'...`);
|
|
377
701
|
try {
|
|
378
702
|
const userId = await this.getUserId();
|
|
379
703
|
const reviewers = [];
|
|
380
|
-
if (
|
|
381
|
-
const identityId = isGuid(assignee) ? assignee : await this.resolveIdentityId(assignee);
|
|
704
|
+
if (options.assignees && options.assignees.length > 0) for (const assignee of options.assignees) {
|
|
705
|
+
const identityId = this.isGuid(assignee) ? assignee : await this.resolveIdentityId(assignee);
|
|
382
706
|
if (identityId && !reviewers.some((r) => r.id === identityId)) reviewers.push({ id: identityId });
|
|
383
707
|
else logger.warn(`Unable to resolve assignee identity '${assignee}'`);
|
|
384
708
|
}
|
|
385
|
-
logger.info(` - Pushing ${
|
|
386
|
-
const push = await this.
|
|
709
|
+
logger.info(` - Pushing ${options.changes.length} file change(s) to branch '${options.source.branch}'...`);
|
|
710
|
+
const push = await this.inner.git.createPush(options.project, options.repository, {
|
|
387
711
|
refUpdates: [{
|
|
388
|
-
name: `refs/heads/${
|
|
389
|
-
oldObjectId:
|
|
712
|
+
name: `refs/heads/${options.source.branch}`,
|
|
713
|
+
oldObjectId: options.source.commit
|
|
390
714
|
}],
|
|
391
715
|
commits: [{
|
|
392
|
-
comment:
|
|
393
|
-
author:
|
|
394
|
-
changes:
|
|
716
|
+
comment: options.commitMessage,
|
|
717
|
+
author: options.author,
|
|
718
|
+
changes: options.changes.filter((change) => change.changeType !== "none").map(({ changeType, ...change }) => {
|
|
395
719
|
return {
|
|
396
720
|
changeType,
|
|
397
721
|
item: { path: normalizeFilePath(change.path) },
|
|
398
|
-
newContent: changeType !==
|
|
722
|
+
newContent: changeType !== "delete" ? {
|
|
399
723
|
content: Buffer.from(change.content, change.encoding).toString("base64"),
|
|
400
|
-
contentType:
|
|
724
|
+
contentType: "base64encoded"
|
|
401
725
|
} : void 0
|
|
402
726
|
};
|
|
403
727
|
})
|
|
@@ -405,37 +729,31 @@ var AzureDevOpsWebApiClient = class AzureDevOpsWebApiClient {
|
|
|
405
729
|
});
|
|
406
730
|
if (!push?.commits?.length) throw new Error("Failed to push changes to source branch, no commits were created");
|
|
407
731
|
logger.info(` - Pushed commit: ${push.commits.map((c) => c.commitId).join(", ")}.`);
|
|
408
|
-
logger.info(` - Creating pull request to merge '${
|
|
409
|
-
const pullRequest = await this.
|
|
410
|
-
sourceRefName: `refs/heads/${
|
|
411
|
-
targetRefName: `refs/heads/${
|
|
412
|
-
title:
|
|
413
|
-
description:
|
|
732
|
+
logger.info(` - Creating pull request to merge '${options.source.branch}' into '${options.target.branch}'...`);
|
|
733
|
+
const pullRequest = await this.inner.pullRequests.create(options.project, options.repository, {
|
|
734
|
+
sourceRefName: `refs/heads/${options.source.branch}`,
|
|
735
|
+
targetRefName: `refs/heads/${options.target.branch}`,
|
|
736
|
+
title: options.title,
|
|
737
|
+
description: options.description,
|
|
414
738
|
reviewers,
|
|
415
|
-
workItemRefs:
|
|
416
|
-
labels:
|
|
739
|
+
workItemRefs: options.workItems?.map((id) => ({ id })),
|
|
740
|
+
labels: options.labels?.map((label) => ({ name: label }))
|
|
417
741
|
});
|
|
418
742
|
if (!pullRequest?.pullRequestId) throw new Error("Failed to create pull request, no pull request id was returned");
|
|
419
743
|
logger.info(` - Created pull request: #${pullRequest.pullRequestId}.`);
|
|
420
|
-
if (
|
|
744
|
+
if (options.properties && options.properties.length > 0) {
|
|
421
745
|
logger.info(` - Adding dependency metadata to pull request properties...`);
|
|
422
|
-
if (!(await this.
|
|
423
|
-
return {
|
|
424
|
-
op: "add",
|
|
425
|
-
path: `/${property.name}`,
|
|
426
|
-
value: property.value
|
|
427
|
-
};
|
|
428
|
-
}), "application/json-patch+json"))?.count) throw new Error("Failed to add dependency metadata properties to pull request");
|
|
746
|
+
if (!(await this.inner.pullRequests.setProperties(options.project, options.repository, pullRequest.pullRequestId, options.properties))?.count) throw new Error("Failed to add dependency metadata properties to pull request");
|
|
429
747
|
}
|
|
430
|
-
if (
|
|
748
|
+
if (options.autoComplete) {
|
|
431
749
|
logger.info(` - Updating auto-complete options...`);
|
|
432
|
-
const updatedPullRequest = await this.
|
|
750
|
+
const updatedPullRequest = await this.inner.pullRequests.update(options.project, options.repository, pullRequest.pullRequestId, {
|
|
433
751
|
autoCompleteSetBy: { id: userId },
|
|
434
752
|
completionOptions: {
|
|
435
|
-
autoCompleteIgnoreConfigIds:
|
|
753
|
+
autoCompleteIgnoreConfigIds: options.autoComplete.ignorePolicyConfigIds,
|
|
436
754
|
deleteSourceBranch: true,
|
|
437
|
-
mergeCommitMessage: mergeCommitMessage(pullRequest.pullRequestId,
|
|
438
|
-
mergeStrategy:
|
|
755
|
+
mergeCommitMessage: this.mergeCommitMessage(pullRequest.pullRequestId, options.title, options.description),
|
|
756
|
+
mergeStrategy: options.autoComplete.mergeStrategy,
|
|
439
757
|
transitionWorkItems: false
|
|
440
758
|
}
|
|
441
759
|
});
|
|
@@ -450,29 +768,29 @@ var AzureDevOpsWebApiClient = class AzureDevOpsWebApiClient {
|
|
|
450
768
|
}
|
|
451
769
|
}
|
|
452
770
|
/**
|
|
453
|
-
* Update
|
|
771
|
+
* Update an existing pull request with new changes.
|
|
772
|
+
* This method performs the following operations:
|
|
773
|
+
* 1. Validates the pull request hasn't been modified by another author
|
|
774
|
+
* 2. Checks if the source branch is behind the target branch
|
|
775
|
+
* 3. Rebases the target branch into the source branch if needed
|
|
776
|
+
* 4. Pushes the new changes to the source branch
|
|
777
|
+
*
|
|
454
778
|
* Requires scope "Code (Read & Write)" (vso.code, vso.code_write).
|
|
455
|
-
* @param
|
|
456
|
-
* @returns
|
|
779
|
+
* @param options Pull request update options including the commit and changes
|
|
780
|
+
* @returns True if successful, false on error
|
|
457
781
|
*/
|
|
458
|
-
async updatePullRequest(
|
|
459
|
-
logger.info(`Updating pull request #${
|
|
782
|
+
async updatePullRequest(options) {
|
|
783
|
+
logger.info(`Updating pull request #${options.pullRequestId}...`);
|
|
460
784
|
try {
|
|
461
|
-
const pullRequest = await this.
|
|
462
|
-
if (!pullRequest) throw new Error(`Pull request #${
|
|
463
|
-
if (
|
|
464
|
-
logger.info(` - Skipping update as pull request
|
|
785
|
+
const pullRequest = await this.inner.pullRequests.get(options.project, options.repository, options.pullRequestId);
|
|
786
|
+
if (!pullRequest) throw new Error(`Pull request #${options.pullRequestId} not found`);
|
|
787
|
+
if ((await this.inner.pullRequests.getCommits(options.project, options.repository, options.pullRequestId))?.some((c) => c.author?.email !== options.author.email)) {
|
|
788
|
+
logger.info(` - Skipping update as pull request has been modified by another user.`);
|
|
465
789
|
return true;
|
|
466
790
|
}
|
|
467
|
-
|
|
468
|
-
if ((await this.restApiGet(`${this.organisationApiUrl}/${pr.project}/_apis/git/repositories/${pr.repository}/pullrequests/${pr.pullRequestId}/commits`))?.value?.some((c) => c.author?.email !== pr.skipIfCommitsFromAuthorsOtherThan)) {
|
|
469
|
-
logger.info(` - Skipping update as pull request has been modified by another user.`);
|
|
470
|
-
return true;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
const stats = await this.restApiGet(`${this.organisationApiUrl}/${pr.project}/_apis/git/repositories/${pr.repository}/stats/branches`, { name: normalizeBranchName(pullRequest.sourceRefName) });
|
|
791
|
+
const stats = await this.inner.repositories.getBranchStats(options.project, options.repository, normalizeBranchName(pullRequest.sourceRefName));
|
|
474
792
|
if (stats?.behindCount === void 0) throw new Error(`Failed to get branch stats for '${pullRequest.sourceRefName}'`);
|
|
475
|
-
if (
|
|
793
|
+
if (stats.behindCount === 0) {
|
|
476
794
|
logger.info(` - Skipping update as source branch is not behind target branch.`);
|
|
477
795
|
return true;
|
|
478
796
|
}
|
|
@@ -480,28 +798,28 @@ var AzureDevOpsWebApiClient = class AzureDevOpsWebApiClient {
|
|
|
480
798
|
const targetBranchName = normalizeBranchName(pullRequest.targetRefName);
|
|
481
799
|
if (stats.behindCount > 0) {
|
|
482
800
|
logger.info(` - Rebasing '${targetBranchName}' into '${sourceBranchName}' (${stats.behindCount} commit(s) behind)...`);
|
|
483
|
-
if ((await this.
|
|
801
|
+
if ((await this.inner.git.updateRef(options.project, options.repository, [{
|
|
484
802
|
name: pullRequest.sourceRefName,
|
|
485
803
|
oldObjectId: pullRequest.lastMergeSourceCommit.commitId,
|
|
486
|
-
newObjectId:
|
|
487
|
-
}]))?.
|
|
804
|
+
newObjectId: options.commit
|
|
805
|
+
}]))?.[0]?.success !== true) throw new Error("Failed to rebase the target branch into the source branch");
|
|
488
806
|
}
|
|
489
|
-
logger.info(` - Pushing ${
|
|
490
|
-
const push = await this.
|
|
807
|
+
logger.info(` - Pushing ${options.changes.length} file change(s) to branch '${pullRequest.sourceRefName}'...`);
|
|
808
|
+
const push = await this.inner.git.createPush(options.project, options.repository, {
|
|
491
809
|
refUpdates: [{
|
|
492
810
|
name: pullRequest.sourceRefName,
|
|
493
|
-
oldObjectId:
|
|
811
|
+
oldObjectId: options.commit
|
|
494
812
|
}],
|
|
495
813
|
commits: [{
|
|
496
|
-
comment: pullRequest.mergeStatus ===
|
|
497
|
-
author:
|
|
498
|
-
changes:
|
|
814
|
+
comment: pullRequest.mergeStatus === "conflicts" ? "Resolve merge conflicts" : `Rebase '${sourceBranchName}' onto '${targetBranchName}'`,
|
|
815
|
+
author: options.author,
|
|
816
|
+
changes: options.changes.filter((change) => change.changeType !== "none").map(({ changeType, ...change }) => {
|
|
499
817
|
return {
|
|
500
818
|
changeType,
|
|
501
819
|
item: { path: normalizeFilePath(change.path) },
|
|
502
|
-
newContent: changeType !==
|
|
820
|
+
newContent: changeType !== "delete" ? {
|
|
503
821
|
content: Buffer.from(change.content, change.encoding).toString("base64"),
|
|
504
|
-
contentType:
|
|
822
|
+
contentType: "base64encoded"
|
|
505
823
|
} : void 0
|
|
506
824
|
};
|
|
507
825
|
})
|
|
@@ -518,20 +836,19 @@ var AzureDevOpsWebApiClient = class AzureDevOpsWebApiClient {
|
|
|
518
836
|
}
|
|
519
837
|
}
|
|
520
838
|
/**
|
|
521
|
-
* Approve a pull request.
|
|
839
|
+
* Approve a pull request as the authenticated user.
|
|
840
|
+
* Sets the reviewer vote to 10 (approved).
|
|
841
|
+
*
|
|
522
842
|
* Requires scope "Code (Write)" (vso.code_write).
|
|
523
|
-
* @param
|
|
524
|
-
* @returns
|
|
843
|
+
* @param options Pull request identification options
|
|
844
|
+
* @returns True if successful, false on error
|
|
525
845
|
*/
|
|
526
|
-
async approvePullRequest(
|
|
527
|
-
logger.info(`Approving pull request #${
|
|
846
|
+
async approvePullRequest(options) {
|
|
847
|
+
logger.info(`Approving pull request #${options.pullRequestId}...`);
|
|
528
848
|
try {
|
|
529
849
|
logger.info(` - Updating reviewer vote on pull request...`);
|
|
530
850
|
const userId = await this.getUserId();
|
|
531
|
-
if ((await this.
|
|
532
|
-
vote: 10,
|
|
533
|
-
isReapprove: true
|
|
534
|
-
}, "7.1"))?.vote !== 10) throw new Error("Failed to approve pull request, vote was not recorded");
|
|
851
|
+
if ((await this.inner.pullRequests.approve(options.project, options.repository, options.pullRequestId, userId))?.vote !== 10) throw new Error("Failed to approve pull request, vote was not recorded");
|
|
535
852
|
logger.info(` - Pull request was approved successfully.`);
|
|
536
853
|
return true;
|
|
537
854
|
} catch (e) {
|
|
@@ -541,37 +858,39 @@ var AzureDevOpsWebApiClient = class AzureDevOpsWebApiClient {
|
|
|
541
858
|
}
|
|
542
859
|
}
|
|
543
860
|
/**
|
|
544
|
-
* Abandon a pull request.
|
|
861
|
+
* Abandon a pull request and optionally delete its source branch.
|
|
862
|
+
* This method performs the following operations:
|
|
863
|
+
* 1. Adds an optional comment explaining the abandonment reason
|
|
864
|
+
* 2. Sets the pull request status to abandoned
|
|
865
|
+
* 3. Deletes the source branch if requested
|
|
866
|
+
*
|
|
545
867
|
* Requires scope "Code (Write)" (vso.code_write).
|
|
546
|
-
* @param
|
|
547
|
-
* @returns
|
|
868
|
+
* @param options Pull request abandonment options including optional comment and branch deletion flag
|
|
869
|
+
* @returns True if successful, false on error
|
|
548
870
|
*/
|
|
549
|
-
async abandonPullRequest(
|
|
550
|
-
logger.info(`Abandoning pull request #${
|
|
871
|
+
async abandonPullRequest(options) {
|
|
872
|
+
logger.info(`Abandoning pull request #${options.pullRequestId}...`);
|
|
551
873
|
try {
|
|
552
874
|
const userId = await this.getUserId();
|
|
553
|
-
if (
|
|
875
|
+
if (options.comment) {
|
|
554
876
|
logger.info(` - Adding abandonment reason comment to pull request...`);
|
|
555
877
|
if (!await this.addCommentThread({
|
|
556
|
-
...
|
|
557
|
-
content:
|
|
878
|
+
...options,
|
|
879
|
+
content: options.comment,
|
|
558
880
|
userId
|
|
559
881
|
})) throw new Error("Failed to add comment to pull request, thread was not created");
|
|
560
882
|
}
|
|
561
883
|
logger.info(` - Abandoning pull request...`);
|
|
562
|
-
const abandonedPullRequest = await this.
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
});
|
|
566
|
-
if (abandonedPullRequest?.status?.toLowerCase() !== "abandoned") throw new Error("Failed to abandon pull request, status was not updated");
|
|
567
|
-
if (pr.deleteSourceBranch) {
|
|
884
|
+
const abandonedPullRequest = await this.inner.pullRequests.abandon(options.project, options.repository, options.pullRequestId, userId);
|
|
885
|
+
if (abandonedPullRequest?.status !== "abandoned") throw new Error("Failed to abandon pull request, status was not updated");
|
|
886
|
+
if (options.deleteSourceBranch) {
|
|
568
887
|
logger.info(` - Deleting source branch...`);
|
|
569
|
-
if ((await this.
|
|
888
|
+
if ((await this.inner.git.updateRef(options.project, options.repository, [{
|
|
570
889
|
name: abandonedPullRequest.sourceRefName,
|
|
571
890
|
oldObjectId: abandonedPullRequest.lastMergeSourceCommit.commitId,
|
|
572
891
|
newObjectId: "0000000000000000000000000000000000000000",
|
|
573
892
|
isLocked: false
|
|
574
|
-
}]))?.
|
|
893
|
+
}]))?.[0]?.success !== true) throw new Error("Failed to delete the source branch");
|
|
575
894
|
}
|
|
576
895
|
logger.info(` - Pull request was abandoned successfully.`);
|
|
577
896
|
return true;
|
|
@@ -583,117 +902,149 @@ var AzureDevOpsWebApiClient = class AzureDevOpsWebApiClient {
|
|
|
583
902
|
}
|
|
584
903
|
/**
|
|
585
904
|
* Add a comment thread on a pull request.
|
|
905
|
+
* The comment thread is created with a closed status and system comment type.
|
|
906
|
+
*
|
|
586
907
|
* Requires scope "Code (Write)" (vso.code_write).
|
|
908
|
+
* @param options Comment creation options including content and optional user ID
|
|
909
|
+
* @returns The created thread ID, or undefined on error
|
|
587
910
|
*/
|
|
588
|
-
async addCommentThread(
|
|
589
|
-
const userId =
|
|
590
|
-
return (await this.
|
|
591
|
-
status:
|
|
911
|
+
async addCommentThread(options) {
|
|
912
|
+
const userId = options.userId ?? await this.getUserId();
|
|
913
|
+
return (await this.inner.pullRequests.createCommentThread(options.project, options.repository, options.pullRequestId, {
|
|
914
|
+
status: "closed",
|
|
592
915
|
comments: [{
|
|
593
916
|
author: { id: userId },
|
|
594
|
-
content:
|
|
595
|
-
commentType:
|
|
917
|
+
content: options.content,
|
|
918
|
+
commentType: "system"
|
|
596
919
|
}]
|
|
597
920
|
}))?.id;
|
|
598
921
|
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
return await sendRestApiRequestWithRetry("PUT", fullUrl, data, async () => {
|
|
629
|
-
return await fetch(fullUrl, {
|
|
630
|
-
method: "PUT",
|
|
631
|
-
headers: {
|
|
632
|
-
"Content-Type": "application/json",
|
|
633
|
-
Authorization: `Basic ${Buffer.from(`:${this.accessToken}`).toString("base64")}`
|
|
634
|
-
},
|
|
635
|
-
body: JSON.stringify(data)
|
|
922
|
+
/**
|
|
923
|
+
* Create or update webhook subscriptions for Azure DevOps events.
|
|
924
|
+
* This sets up subscriptions for various git events (push, pull request updates, repository changes, etc.)
|
|
925
|
+
* and ensures they are configured to send webhooks to the specified URL.
|
|
926
|
+
* Existing subscriptions matching the URL will be updated, otherwise new subscriptions are created.
|
|
927
|
+
*
|
|
928
|
+
* Requires scope "Service Hooks (Read & Write)" (vso.hooks_write).
|
|
929
|
+
* @returns Array of subscription IDs that were created or updated
|
|
930
|
+
*/
|
|
931
|
+
async createOrUpdateHookSubscriptions({ url, headers, project }) {
|
|
932
|
+
const subscriptionTypes = new Map([
|
|
933
|
+
["git.push", "1.0"],
|
|
934
|
+
["git.pullrequest.updated", "1.0"],
|
|
935
|
+
["git.pullrequest.merged", "1.0"],
|
|
936
|
+
["git.repo.created", "1.0-preview.1"],
|
|
937
|
+
["git.repo.deleted", "1.0-preview.1"],
|
|
938
|
+
["git.repo.renamed", "1.0-preview.1"],
|
|
939
|
+
["git.repo.statuschanged", "1.0-preview.1"],
|
|
940
|
+
["ms.vss-code.git-pullrequest-comment-event", "2.0"]
|
|
941
|
+
]);
|
|
942
|
+
const query = this.buildSubscriptionsQuery({
|
|
943
|
+
url,
|
|
944
|
+
project
|
|
945
|
+
});
|
|
946
|
+
const subscriptions = await this.inner.subscriptions.query(query);
|
|
947
|
+
const ids = [];
|
|
948
|
+
for (const [eventType, resourceVersion] of subscriptionTypes) {
|
|
949
|
+
const existing = subscriptions.find((sub) => {
|
|
950
|
+
return sub.eventType === eventType && sub.resourceVersion === resourceVersion;
|
|
636
951
|
});
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
952
|
+
let subscription;
|
|
953
|
+
if (existing) {
|
|
954
|
+
existing.status = "enabled";
|
|
955
|
+
existing.eventType = eventType;
|
|
956
|
+
existing.resourceVersion = resourceVersion;
|
|
957
|
+
existing.publisherInputs = this.makeTfsPublisherInputs({
|
|
958
|
+
eventType,
|
|
959
|
+
project
|
|
960
|
+
});
|
|
961
|
+
existing.consumerInputs = this.makeWebhookConsumerInputs({
|
|
962
|
+
url,
|
|
963
|
+
headers
|
|
964
|
+
});
|
|
965
|
+
subscription = await this.inner.subscriptions.replace(existing.id, existing);
|
|
966
|
+
} else subscription = await this.inner.subscriptions.create({
|
|
967
|
+
status: "enabled",
|
|
968
|
+
eventType,
|
|
969
|
+
resourceVersion,
|
|
970
|
+
publisherId: "tfs",
|
|
971
|
+
publisherInputs: this.makeTfsPublisherInputs({
|
|
972
|
+
eventType,
|
|
973
|
+
project
|
|
974
|
+
}),
|
|
975
|
+
consumerId: "webHooks",
|
|
976
|
+
consumerActionId: "httpRequest",
|
|
977
|
+
consumerInputs: this.makeWebhookConsumerInputs({
|
|
978
|
+
url,
|
|
979
|
+
headers
|
|
980
|
+
})
|
|
649
981
|
});
|
|
650
|
-
|
|
651
|
-
}
|
|
652
|
-
};
|
|
653
|
-
function mergeCommitMessage(id, title, description) {
|
|
654
|
-
return `Merged PR ${id}: ${title}\n\n${description}`.slice(0, 3500);
|
|
655
|
-
}
|
|
656
|
-
function isGuid(guid) {
|
|
657
|
-
return /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(guid);
|
|
658
|
-
}
|
|
659
|
-
function getIdentityApiUrl(organisationApiUrl) {
|
|
660
|
-
const uri = new URL(organisationApiUrl);
|
|
661
|
-
const hostname = uri.hostname.toLowerCase();
|
|
662
|
-
if (hostname === "dev.azure.com" || hostname.endsWith(".visualstudio.com")) uri.host = "vssps.dev.azure.com";
|
|
663
|
-
return uri.toString();
|
|
664
|
-
}
|
|
665
|
-
async function sendRestApiRequestWithRetry(method, url, payload, requestAsync, isDebug = false, retryCount = 3, retryDelay = 3e3) {
|
|
666
|
-
let body;
|
|
667
|
-
try {
|
|
668
|
-
if (isDebug) logger.debug(`🌎 🠊 [${method}] ${url}`);
|
|
669
|
-
const response = await requestAsync();
|
|
670
|
-
body = await response.text();
|
|
671
|
-
const { status: statusCode, statusText: statusMessage } = response;
|
|
672
|
-
if (isDebug) logger.debug(`🌎 🠈 [${statusCode}] ${statusMessage}`);
|
|
673
|
-
if (statusCode < 200 || statusCode > 299) throw new HttpRequestError(`HTTP ${method} '${url}' failed: ${statusCode} ${statusMessage}`, statusCode);
|
|
674
|
-
return JSON.parse(body);
|
|
675
|
-
} catch (e) {
|
|
676
|
-
const err = e;
|
|
677
|
-
if (retryCount > 1 && isErrorTemporaryFailure(err)) {
|
|
678
|
-
logger.warn(err.message);
|
|
679
|
-
if (isDebug) logger.debug(`⏳ Retrying request in ${retryDelay}ms...`);
|
|
680
|
-
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
681
|
-
return sendRestApiRequestWithRetry(method, url, payload, requestAsync, isDebug, retryCount - 1, retryDelay);
|
|
982
|
+
ids.push(subscription.id);
|
|
682
983
|
}
|
|
683
|
-
if (
|
|
684
|
-
if (payload) logger.debug(`REQUEST: ${JSON.stringify(payload)}`);
|
|
685
|
-
if (body) logger.debug(`RESPONSE: ${body}`);
|
|
686
|
-
}
|
|
687
|
-
logger.trace(`THROW${e}`);
|
|
688
|
-
throw e;
|
|
984
|
+
for (const sub of subscriptions) if (!ids.includes(sub.id)) await this.inner.subscriptions.delete(sub.id);
|
|
689
985
|
}
|
|
690
|
-
|
|
986
|
+
/**
|
|
987
|
+
* Remove all webhook subscriptions for a specific URL.
|
|
988
|
+
* This finds all subscriptions matching the provided URL and deletes them.
|
|
989
|
+
*
|
|
990
|
+
* Requires scope "Service Hooks (Read & Write)" (vso.hooks_write).
|
|
991
|
+
*/
|
|
992
|
+
async deleteHookSubscriptions({ url, project }) {
|
|
993
|
+
const query = this.buildSubscriptionsQuery({
|
|
994
|
+
url,
|
|
995
|
+
project
|
|
996
|
+
});
|
|
997
|
+
const subscriptions = await this.inner.subscriptions.query(query);
|
|
998
|
+
for (const sub of subscriptions) await this.inner.subscriptions.delete(sub.id);
|
|
999
|
+
}
|
|
1000
|
+
mergeCommitMessage(id, title, description) {
|
|
1001
|
+
return `Merged PR ${id}: ${title}\n\n${description}`.slice(0, 3500);
|
|
1002
|
+
}
|
|
1003
|
+
isGuid(guid) {
|
|
1004
|
+
return /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(guid);
|
|
1005
|
+
}
|
|
1006
|
+
buildSubscriptionsQuery({ url, project }) {
|
|
1007
|
+
return {
|
|
1008
|
+
publisherId: "tfs",
|
|
1009
|
+
publisherInputFilters: [{ conditions: [{
|
|
1010
|
+
operator: "equals",
|
|
1011
|
+
inputId: "projectId",
|
|
1012
|
+
caseSensitive: false,
|
|
1013
|
+
inputValue: project
|
|
1014
|
+
}] }],
|
|
1015
|
+
consumerId: "webHooks",
|
|
1016
|
+
consumerActionId: "httpRequest",
|
|
1017
|
+
consumerInputFilters: [{ conditions: [{
|
|
1018
|
+
operator: "equals",
|
|
1019
|
+
inputId: "url",
|
|
1020
|
+
caseSensitive: false,
|
|
1021
|
+
inputValue: url
|
|
1022
|
+
}] }]
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
makeTfsPublisherInputs({ eventType, project }) {
|
|
1026
|
+
return {
|
|
1027
|
+
projectId: project,
|
|
1028
|
+
...eventType === "git.pullrequest.updated" && { notificationType: "StatusUpdateNotification" },
|
|
1029
|
+
...eventType === "git.pullrequest.merged" && { mergeResult: "Conflicts" }
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
makeWebhookConsumerInputs({ url, headers }) {
|
|
1033
|
+
return {
|
|
1034
|
+
url,
|
|
1035
|
+
acceptUntrustedCerts: "false",
|
|
1036
|
+
httpHeaders: Object.entries(headers).map(([key, value]) => `${key}:${value}`).join("\n"),
|
|
1037
|
+
messagesToSend: "none",
|
|
1038
|
+
detailedMessagesToSend: "none"
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
};
|
|
691
1042
|
|
|
692
1043
|
//#endregion
|
|
693
1044
|
//#region src/azure/config.ts
|
|
694
1045
|
/**
|
|
695
1046
|
* Parse the dependabot config YAML file to specify update configuration.
|
|
696
|
-
* The file should be located at any of `
|
|
1047
|
+
* The file should be located at any of `CONFIG_FILE_PATHS_AZURE`.
|
|
697
1048
|
*
|
|
698
1049
|
* To view YAML file format, visit
|
|
699
1050
|
* https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#allow
|
|
@@ -705,15 +1056,22 @@ async function getDependabotConfig({ url, token, remote, rootDir = process.cwd()
|
|
|
705
1056
|
let configContents;
|
|
706
1057
|
if (remote) {
|
|
707
1058
|
logger.debug(`Attempting to fetch configuration file via REST API ...`);
|
|
708
|
-
for (const fp of
|
|
1059
|
+
for (const fp of CONFIG_FILE_PATHS_AZURE) {
|
|
709
1060
|
const requestUrl = `${url.value}${url.project}/_apis/git/repositories/${url.repository}/items?path=/${fp}`;
|
|
710
1061
|
logger.debug(`GET ${requestUrl}`);
|
|
711
1062
|
try {
|
|
712
1063
|
const authHeader = `Basic ${Buffer.from(`x-access-token:${token}`).toString("base64")}`;
|
|
713
|
-
const response = await
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
1064
|
+
const response = await ky.get(requestUrl, {
|
|
1065
|
+
headers: {
|
|
1066
|
+
Authorization: authHeader,
|
|
1067
|
+
Accept: "*/*"
|
|
1068
|
+
},
|
|
1069
|
+
throwHttpErrors: (status) => ![
|
|
1070
|
+
401,
|
|
1071
|
+
403,
|
|
1072
|
+
404
|
|
1073
|
+
].includes(status)
|
|
1074
|
+
});
|
|
717
1075
|
if (response.ok) {
|
|
718
1076
|
logger.debug(`Found configuration file at '${requestUrl}'`);
|
|
719
1077
|
configContents = await response.text();
|
|
@@ -729,7 +1087,7 @@ async function getDependabotConfig({ url, token, remote, rootDir = process.cwd()
|
|
|
729
1087
|
else throw error;
|
|
730
1088
|
}
|
|
731
1089
|
}
|
|
732
|
-
} else for (const fp of
|
|
1090
|
+
} else for (const fp of CONFIG_FILE_PATHS_AZURE) {
|
|
733
1091
|
const filePath = path.join(rootDir, fp);
|
|
734
1092
|
if (existsSync(filePath)) {
|
|
735
1093
|
logger.debug(`Found configuration file cloned at ${filePath}`);
|
|
@@ -738,7 +1096,7 @@ async function getDependabotConfig({ url, token, remote, rootDir = process.cwd()
|
|
|
738
1096
|
break;
|
|
739
1097
|
} else logger.trace(`No configuration file cloned at ${filePath}`);
|
|
740
1098
|
}
|
|
741
|
-
if (!configContents || !configPath || typeof configContents !== "string") throw new Error(`Configuration file not found at possible locations: ${
|
|
1099
|
+
if (!configContents || !configPath || typeof configContents !== "string") throw new Error(`Configuration file not found at possible locations: ${CONFIG_FILE_PATHS_AZURE.join(", ")}`);
|
|
742
1100
|
else logger.trace("Configuration file contents read.");
|
|
743
1101
|
return await parseDependabotConfig({
|
|
744
1102
|
configContents,
|
|
@@ -747,6 +1105,119 @@ async function getDependabotConfig({ url, token, remote, rootDir = process.cwd()
|
|
|
747
1105
|
});
|
|
748
1106
|
}
|
|
749
1107
|
|
|
1108
|
+
//#endregion
|
|
1109
|
+
//#region src/azure/events.ts
|
|
1110
|
+
const AzdoEventTypeSchema = z.enum([
|
|
1111
|
+
"git.push",
|
|
1112
|
+
"git.pullrequest.updated",
|
|
1113
|
+
"git.pullrequest.merged",
|
|
1114
|
+
"git.repo.created",
|
|
1115
|
+
"git.repo.deleted",
|
|
1116
|
+
"git.repo.renamed",
|
|
1117
|
+
"git.repo.statuschanged",
|
|
1118
|
+
"ms.vss-code.git-pullrequest-comment-event"
|
|
1119
|
+
]);
|
|
1120
|
+
const AzdoEventProjectSchema = z.object({
|
|
1121
|
+
id: z.string(),
|
|
1122
|
+
name: z.string(),
|
|
1123
|
+
url: z.string()
|
|
1124
|
+
});
|
|
1125
|
+
const AzdoEventRepositorySchema = z.object({
|
|
1126
|
+
id: z.string(),
|
|
1127
|
+
name: z.string(),
|
|
1128
|
+
project: AzdoEventProjectSchema,
|
|
1129
|
+
defaultBranch: z.string().optional(),
|
|
1130
|
+
remoteUrl: z.string()
|
|
1131
|
+
});
|
|
1132
|
+
const AzdoEventCodePushResourceSchema = z.object({
|
|
1133
|
+
repository: AzdoEventRepositorySchema,
|
|
1134
|
+
commits: AzdoGitCommitRefSchema.array(),
|
|
1135
|
+
refUpdates: z.object({
|
|
1136
|
+
name: z.string(),
|
|
1137
|
+
oldObjectId: z.string().nullish(),
|
|
1138
|
+
newObjectId: z.string().nullish()
|
|
1139
|
+
}).array(),
|
|
1140
|
+
pushId: z.number(),
|
|
1141
|
+
url: z.string()
|
|
1142
|
+
});
|
|
1143
|
+
const AzdoEventPullRequestResourceSchema = z.object({
|
|
1144
|
+
repository: AzdoEventRepositorySchema,
|
|
1145
|
+
pullRequestId: z.number(),
|
|
1146
|
+
status: AzdoPullRequestStatusSchema,
|
|
1147
|
+
createdBy: AzdoIdentityRefSchema,
|
|
1148
|
+
title: z.string(),
|
|
1149
|
+
sourceRefName: z.string(),
|
|
1150
|
+
targetRefName: z.string(),
|
|
1151
|
+
mergeStatus: AzdoPullRequestAsyncStatusSchema,
|
|
1152
|
+
mergeId: z.string(),
|
|
1153
|
+
url: z.string()
|
|
1154
|
+
});
|
|
1155
|
+
const AzdoEventRepositoryCreatedResourceSchema = z.object({ repository: AzdoEventRepositorySchema });
|
|
1156
|
+
const AzdoEventRepositoryDeletedResourceSchema = z.object({
|
|
1157
|
+
project: AzdoEventProjectSchema,
|
|
1158
|
+
repositoryId: z.string(),
|
|
1159
|
+
repositoryName: z.string(),
|
|
1160
|
+
isHardDelete: z.boolean()
|
|
1161
|
+
});
|
|
1162
|
+
const AzdoEventRepositoryRenamedResourceSchema = z.object({
|
|
1163
|
+
oldName: z.string(),
|
|
1164
|
+
newName: z.string(),
|
|
1165
|
+
repository: AzdoEventRepositorySchema
|
|
1166
|
+
});
|
|
1167
|
+
const AzdoEventRepositoryStatusChangedResourceSchema = z.object({
|
|
1168
|
+
disabled: z.boolean(),
|
|
1169
|
+
repository: AzdoEventRepositorySchema
|
|
1170
|
+
});
|
|
1171
|
+
const AzdoEventPullRequestCommentEventResourceSchema = z.object({
|
|
1172
|
+
pullRequest: AzdoEventPullRequestResourceSchema,
|
|
1173
|
+
comment: AzdoPullRequestCommentSchema
|
|
1174
|
+
});
|
|
1175
|
+
const AzdoEventSchema = z.object({
|
|
1176
|
+
subscriptionId: z.string(),
|
|
1177
|
+
notificationId: z.number(),
|
|
1178
|
+
id: z.string(),
|
|
1179
|
+
publisherId: z.string(),
|
|
1180
|
+
resourceVersion: z.enum([
|
|
1181
|
+
"1.0",
|
|
1182
|
+
"1.0-preview.1",
|
|
1183
|
+
"2.0"
|
|
1184
|
+
]),
|
|
1185
|
+
createdDate: z.coerce.date()
|
|
1186
|
+
}).and(z.discriminatedUnion("eventType", [
|
|
1187
|
+
z.object({
|
|
1188
|
+
eventType: z.literal("git.push"),
|
|
1189
|
+
resource: AzdoEventCodePushResourceSchema
|
|
1190
|
+
}),
|
|
1191
|
+
z.object({
|
|
1192
|
+
eventType: z.literal("git.pullrequest.updated"),
|
|
1193
|
+
resource: AzdoEventPullRequestResourceSchema
|
|
1194
|
+
}),
|
|
1195
|
+
z.object({
|
|
1196
|
+
eventType: z.literal("git.pullrequest.merged"),
|
|
1197
|
+
resource: AzdoEventPullRequestResourceSchema
|
|
1198
|
+
}),
|
|
1199
|
+
z.object({
|
|
1200
|
+
eventType: z.literal("git.repo.created"),
|
|
1201
|
+
resource: AzdoEventRepositoryCreatedResourceSchema
|
|
1202
|
+
}),
|
|
1203
|
+
z.object({
|
|
1204
|
+
eventType: z.literal("git.repo.deleted"),
|
|
1205
|
+
resource: AzdoEventRepositoryDeletedResourceSchema
|
|
1206
|
+
}),
|
|
1207
|
+
z.object({
|
|
1208
|
+
eventType: z.literal("git.repo.renamed"),
|
|
1209
|
+
resource: AzdoEventRepositoryRenamedResourceSchema
|
|
1210
|
+
}),
|
|
1211
|
+
z.object({
|
|
1212
|
+
eventType: z.literal("git.repo.statuschanged"),
|
|
1213
|
+
resource: AzdoEventRepositoryStatusChangedResourceSchema
|
|
1214
|
+
}),
|
|
1215
|
+
z.object({
|
|
1216
|
+
eventType: z.literal("ms.vss-code.git-pullrequest-comment-event"),
|
|
1217
|
+
resource: AzdoEventPullRequestCommentEventResourceSchema
|
|
1218
|
+
})
|
|
1219
|
+
]));
|
|
1220
|
+
|
|
750
1221
|
//#endregion
|
|
751
1222
|
//#region src/azure/url-parts.ts
|
|
752
1223
|
function extractOrganizationUrl({ organisationUrl }) {
|
|
@@ -757,12 +1228,14 @@ function extractOrganizationUrl({ organisationUrl }) {
|
|
|
757
1228
|
const organisation = extractOrganisation(organisationUrl);
|
|
758
1229
|
const virtualDirectory = extractVirtualDirectory(value);
|
|
759
1230
|
const apiEndpoint = `${protocol}://${hostname}${value.port ? `:${value.port}` : ""}/${virtualDirectory ? `${virtualDirectory}/` : ""}`;
|
|
1231
|
+
const identityApiUrl = hostname === "dev.azure.com" || hostname.endsWith(".visualstudio.com") ? new URL(`https://vssps.dev.azure.com/${organisation}/`) : value;
|
|
760
1232
|
return {
|
|
761
1233
|
value,
|
|
762
1234
|
hostname,
|
|
763
1235
|
"api-endpoint": apiEndpoint,
|
|
764
1236
|
organisation,
|
|
765
|
-
"virtual-directory": virtualDirectory
|
|
1237
|
+
"virtual-directory": virtualDirectory,
|
|
1238
|
+
"identity-api-url": identityApiUrl
|
|
766
1239
|
};
|
|
767
1240
|
}
|
|
768
1241
|
function extractProjectUrl({ organisationUrl, project }) {
|
|
@@ -818,5 +1291,5 @@ function extractVirtualDirectory(organisationUrl) {
|
|
|
818
1291
|
}
|
|
819
1292
|
|
|
820
1293
|
//#endregion
|
|
821
|
-
export { ANONYMOUS_USER_ID,
|
|
1294
|
+
export { ANONYMOUS_USER_ID, API_VERSION, API_VERSION_PREVIEW, AZDO_PULL_REQUEST_MERGE_STRATEGIES, AzdoCommentThreadStatusSchema, AzdoCommentTypeSchema, AzdoConnectionDataSchema, AzdoEventCodePushResourceSchema, AzdoEventPullRequestCommentEventResourceSchema, AzdoEventPullRequestResourceSchema, AzdoEventRepositoryCreatedResourceSchema, AzdoEventRepositoryDeletedResourceSchema, AzdoEventRepositoryRenamedResourceSchema, AzdoEventRepositorySchema, AzdoEventRepositoryStatusChangedResourceSchema, AzdoEventSchema, AzdoEventTypeSchema, AzdoGitBranchStatsSchema, AzdoGitChangeSchema, AzdoGitCommitDiffsSchema, AzdoGitCommitRefSchema, AzdoGitPushCreateSchema, AzdoGitPushSchema, AzdoGitRefSchema, AzdoGitRefUpdateResultSchema, AzdoGitRefUpdateSchema, AzdoGitUserDateSchema, AzdoIdentityRefSchema, AzdoIdentityRefWithVoteSchema, AzdoIdentitySchema, AzdoProjectSchema, AzdoPropertiesSchema, AzdoPullRequestAsyncStatusSchema, AzdoPullRequestCommentSchema, AzdoPullRequestCommentThreadSchema, AzdoPullRequestMergeStrategySchema, AzdoPullRequestSchema, AzdoPullRequestStatusSchema, AzdoRepositoryItemSchema, AzdoRepositorySchema, AzdoSubscriptionSchema, AzdoSubscriptionsQueryInputFilterSchema, AzdoSubscriptionsQueryResponseSchema, AzdoSubscriptionsQuerySchema, AzdoVersionControlChangeTypeSchema, AzureDevOpsClient, AzureDevOpsClientWrapper, PR_DESCRIPTION_MAX_LENGTH, PR_PROPERTY_DEPENDABOT_DEPENDENCIES, PR_PROPERTY_DEPENDABOT_PACKAGE_MANAGER, PR_PROPERTY_MICROSOFT_GIT_SOURCE_REF_NAME, buildPullRequestProperties, extractOrganizationUrl, extractProjectUrl, extractRepositoryUrl, getDependabotConfig, getPullRequestChangedFiles, getPullRequestForDependencyNames, parsePullRequestProperties };
|
|
822
1295
|
//# sourceMappingURL=index.mjs.map
|