@gitkraken/core-gitlens 0.15.2 → 0.15.4

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 (75) hide show
  1. package/CHANGELOG.md +35 -1
  2. package/dist/git/cache.d.ts +24 -11
  3. package/dist/git/cache.js +44 -16
  4. package/dist/git/cache.js.map +1 -1
  5. package/dist/git/models/issue.d.ts +2 -2
  6. package/dist/git/models/issue.js.map +1 -1
  7. package/dist/git/models/issueOrPullRequest.d.ts +2 -1
  8. package/dist/git/models/pullRequest.d.ts +8 -5
  9. package/dist/git/models/pullRequest.js.map +1 -1
  10. package/dist/git/models/reference.d.ts +8 -0
  11. package/dist/git/providers/branches.d.ts +43 -0
  12. package/dist/git/watching/changeEvent.d.ts +4 -2
  13. package/dist/git/watching/changeEvent.js +3 -1
  14. package/dist/git/watching/changeEvent.js.map +1 -1
  15. package/dist/git/watching/watchGroup.d.ts +3 -3
  16. package/dist/git/watching/watchGroup.js +1 -0
  17. package/dist/git/watching/watchGroup.js.map +1 -1
  18. package/dist/git/watching/watchService.js.map +1 -1
  19. package/dist/git/watching/watchSession.d.ts +2 -1
  20. package/dist/git/watching/watchSession.js +3 -2
  21. package/dist/git/watching/watchSession.js.map +1 -1
  22. package/dist/git/watching/watcherPatterns.js +1 -0
  23. package/dist/git/watching/watcherPatterns.js.map +1 -1
  24. package/dist/git/watching/worktreeSummary.d.ts +19 -3
  25. package/dist/git/watching/worktreeSummary.js +107 -17
  26. package/dist/git/watching/worktreeSummary.js.map +1 -1
  27. package/dist/git-cli/parsers/refParser.js +2 -1
  28. package/dist/git-cli/parsers/refParser.js.map +1 -1
  29. package/dist/git-cli/providers/branches.d.ts +8 -1
  30. package/dist/git-cli/providers/branches.js +84 -12
  31. package/dist/git-cli/providers/branches.js.map +1 -1
  32. package/dist/git-cli/providers/config.d.ts +32 -9
  33. package/dist/git-cli/providers/config.js +113 -24
  34. package/dist/git-cli/providers/config.js.map +1 -1
  35. package/dist/plus/integrations/models/gitHostIntegration.d.ts +29 -14
  36. package/dist/plus/integrations/models/gitHostIntegration.js +41 -19
  37. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  38. package/dist/plus/integrations/models/integration.d.ts +1 -1
  39. package/dist/plus/integrations/models/integration.js.map +1 -1
  40. package/dist/plus/integrations/providers/azure/azure.d.ts +16 -15
  41. package/dist/plus/integrations/providers/azure/azure.js +72 -23
  42. package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
  43. package/dist/plus/integrations/providers/azure/azure.utils.d.ts +12 -0
  44. package/dist/plus/integrations/providers/azure/azure.utils.js +17 -1
  45. package/dist/plus/integrations/providers/azure/azure.utils.js.map +1 -1
  46. package/dist/plus/integrations/providers/azure/models.d.ts +3 -1
  47. package/dist/plus/integrations/providers/azure/models.js +8 -5
  48. package/dist/plus/integrations/providers/azure/models.js.map +1 -1
  49. package/dist/plus/integrations/providers/azure/search.d.ts +10 -4
  50. package/dist/plus/integrations/providers/azure/search.js +74 -11
  51. package/dist/plus/integrations/providers/azure/search.js.map +1 -1
  52. package/dist/plus/integrations/providers/azure/workItemSearch.d.ts +11 -0
  53. package/dist/plus/integrations/providers/azure/workItemSearch.js +54 -0
  54. package/dist/plus/integrations/providers/azure/workItemSearch.js.map +1 -0
  55. package/dist/plus/integrations/providers/azure/workItemStateCategories.d.ts +2 -2
  56. package/dist/plus/integrations/providers/azure/workItemStateCategories.js +19 -15
  57. package/dist/plus/integrations/providers/azure/workItemStateCategories.js.map +1 -1
  58. package/dist/plus/integrations/providers/azureDevOps.d.ts +33 -20
  59. package/dist/plus/integrations/providers/azureDevOps.js +109 -48
  60. package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
  61. package/dist/plus/integrations/providers/azureDevOpsServer.d.ts +16 -47
  62. package/dist/plus/integrations/providers/azureDevOpsServer.js +51 -90
  63. package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
  64. package/dist/plus/integrations/providers/issueSorts.d.ts +1 -0
  65. package/dist/plus/integrations/providers/models.d.ts +5 -0
  66. package/dist/plus/integrations/providers/models.js +25 -11
  67. package/dist/plus/integrations/providers/models.js.map +1 -1
  68. package/dist/plus/integrations/reads/drains.d.ts +3 -2
  69. package/dist/plus/integrations/reads/drains.js +4 -4
  70. package/dist/plus/integrations/reads/drains.js.map +1 -1
  71. package/dist/plus/integrations/reads/issues.js +7 -4
  72. package/dist/plus/integrations/reads/issues.js.map +1 -1
  73. package/dist/plus/integrations/reads/resolveRepository.js +5 -5
  74. package/dist/plus/integrations/reads/resolveRepository.js.map +1 -1
  75. package/package.json +1 -1
@@ -1,14 +1,15 @@
1
1
  import { Emitter } from "../../../utils/event.js";
2
2
  import { IssueSearchCriteria } from "../../../git/models/issue.js";
3
- import { PullRequest, PullRequestSearchCriteria } from "../../../git/models/pullRequest.js";
3
+ import { PullRequestSearchCriteria } from "../../../git/models/pullRequest.js";
4
4
  import { Account } from "../../../git/models/author.js";
5
5
  import { ProviderAuthenticationSession, TokenWithInfo } from "../authentication/models.js";
6
6
  import { GitSelfManagedHostIntegrationId } from "../constants.js";
7
7
  import { ProviderPullRequestCount, ProviderPullRequestSearchPage } from "../models/pullRequestReads.js";
8
- import { ProviderAzureResource, ProviderPullRequest, ProviderRepoInput, ProviderReposInput } from "./models.js";
8
+ import { ProviderAzureResource, ProviderRepoInput, ProviderReposInput } from "./models.js";
9
9
  import { AzureRepositoryDescriptor } from "./azure/models.js";
10
10
  import { ProvidersApi } from "./providersApi.js";
11
11
  import { ProviderIssueSearchPage, ProviderSearchCount } from "../models/issueReads.js";
12
+ import { RepositoryCoordinate } from "../models/gitHostIntegration.js";
12
13
  import { IntegrationKey } from "../models/integration.js";
13
14
  import { IntegrationConnectionChangeEvent } from "../integrationService.js";
14
15
  import { IntegrationAuthenticationService } from "../authentication/integrationAuthenticationService.js";
@@ -45,11 +46,14 @@ export declare class AzureDevOpsServerIntegration extends AzureDevOpsIntegration
45
46
  /** The base a request below `collection` appends to: the installation, whichever the address already ends in. */
46
47
  protected collectionApiBaseUrl(session: ProviderAuthenticationSession, collection: string): string;
47
48
  /**
48
- * The collection names per credential and installation, `undefined` when they couldn't be read. Only a
49
+ * The collection names per credential and installation, `undefined` when they couldn't be read, and whether the
50
+ * address is then presumed to name a collection ({@link requestResourcesForUser}). Only a
49
51
  * tie-breaker for {@link getRepositoryTarget}, so a failed read is kept (for {@link discoveryCacheTtl}) rather than
50
52
  * retried on every repository read; a successful one comes from the organizations, which are kept for the session.
51
53
  */
52
54
  private readonly _collectionNames;
55
+ /** The failures to read the collection an address names after its collection list answered with a 404. */
56
+ private readonly _collectionListRefusals;
53
57
  /**
54
58
  * Settles which segment of a remote's path is the collection before reading the repository. Behind a virtual
55
59
  * directory a repository named after its project is also served as `{vdir}/{collection}/_git/{repo}`, which the
@@ -62,6 +66,8 @@ export declare class AzureDevOpsServerIntegration extends AzureDevOpsIntegration
62
66
  /**
63
67
  * The repository {@link getRepositoryTarget} reads `repo` as, and the base it reads it below: `undefined` when the
64
68
  * connection doesn't serve its virtual directory (another installation's) or that directory isn't a valid one.
69
+ * `isCandidate` is whether `repo` can be project-less below the connection ({@link isAzureProjectlessCandidate} by
70
+ * default), given whether the connection is known to address a collection rather than the installation.
65
71
  */
66
72
  private settleRepository;
67
73
  /**
@@ -71,23 +77,10 @@ export declare class AzureDevOpsServerIntegration extends AzureDevOpsIntegration
71
77
  * Only the coordinate is settled, and only to a repository the connection serves: each read places it below the
72
78
  * connection itself, so one settling elsewhere reads as given and fails its own read rather than every coordinate's.
73
79
  */
74
- protected resolveRepositoryCoordinates<T extends {
75
- owner: string;
76
- repo: string;
77
- project?: string;
78
- }>(session: ProviderAuthenticationSession, coordinates: readonly T[], cancellation?: AbortSignal): Promise<{
80
+ protected resolveRepositoryCoordinates<T extends RepositoryCoordinate>(session: ProviderAuthenticationSession, coordinates: readonly T[], cancellation?: AbortSignal): Promise<{
79
81
  coordinates: readonly T[];
80
82
  unsettled?: readonly boolean[];
81
83
  }>;
82
- /**
83
- * The searches and counts take only `repos`: they re-read the collections and refuse a scope whose collection
84
- * isn't one of them ({@link getSearchCollections}), and a scope read as parsed below a listed collection is what
85
- * settling it would read ({@link resolveAzureProjectlessRepository}), so a miss there is not `unsettled`.
86
- */
87
- protected resolveRepositoryInputs(session: ProviderAuthenticationSession, repos: readonly ProviderRepoInput[], cancellation?: AbortSignal): Promise<{
88
- repos: ProviderRepoInput[];
89
- unsettled?: readonly boolean[];
90
- }>;
91
84
  /**
92
85
  * Never rejects. A credential refused the list leaves every path as parsed, as before discovery was asked; any other
93
86
  * failure is `undefined`, so a read of a path it could have settled keeps a miss out of the caches (see
@@ -98,11 +91,13 @@ export declare class AzureDevOpsServerIntegration extends AzureDevOpsIntegration
98
91
  /**
99
92
  * Only the server level lists the collections: below one, Azure DevOps Server answers `projectCollections` with a
100
93
  * 404 page. On that 404 an address that names a collection reads the collection's own connection data, whose
101
- * `webApplicationRelativeDirectory` spells it, and reports it as the one collection visible there.
94
+ * `webApplicationRelativeDirectory` spells it, and reports it as the one collection visible there. When that read
95
+ * fails, the address is presumed to name a collection, which the failure carries (see {@link getCollectionNames}) for
96
+ * as long as the failed discovery is kept; connection data that answers for the server says it doesn't.
102
97
  */
103
98
  protected requestResourcesForUser(session: ProviderAuthenticationSession, userId: string): Promise<ProviderAzureResource[] | undefined>;
104
99
  /**
105
- * The filtered work-item search: one WIQL query per page over ONE collection, then one detail read for the
100
+ * The filtered work-item search snapshots matching ids with bounded WIQL queries, then reads details for each
106
101
  * page's slice. See {@link resolveWorkItemSearchScope} for why a search never spans several collections.
107
102
  */
108
103
  protected searchProviderIssuesPage(session: ProviderAuthenticationSession, options: {
@@ -196,34 +191,8 @@ export declare class AzureDevOpsServerIntegration extends AzureDevOpsIntegration
196
191
  * user reads every project the account can see, the same breadth as the account-wide pull request read.
197
192
  */
198
193
  private resolvePullRequestSearchFacets;
199
- private readonly _collectionUserIds;
200
- /**
201
- * The current user's identity id in `collection`, read from the collection's own connection data, which is
202
- * what Azure's creator and reviewer filters compare against. Cached per credential and collection, since it
203
- * can't change for either.
204
- */
205
- protected getFilterUserId(session: ProviderAuthenticationSession, collection: string): Promise<string | undefined>;
206
- /**
207
- * Resolved per collection, which a raw row names as its repository owner: a collection's pull requests carry the
208
- * id {@link getFilterUserId} resolves there, never the server-level account's. A row that names no collection or
209
- * has no author to match gets no viewer, nor does one in a collection whose id can't be read: its authorship
210
- * stays unknown.
211
- */
212
- getPullRequestViewers(pullRequests: readonly (ProviderPullRequest | PullRequest)[], connectionId?: string): Promise<({
213
- id: string;
214
- username?: string;
215
- } | undefined)[]>;
216
- /**
217
- * Ignores `account`: it is the server-level one, which no collection's pull requests carry. A collection whose id
218
- * can't be read resolves `undefined`, since authorship is optional enrichment and one collection's failed lookup
219
- * must not fail the read or blank the others; it is asked once per read, as a miss isn't cached.
220
- */
221
- protected getOrganizationViewers(session: ProviderAuthenticationSession, _account: {
222
- id: string;
223
- username?: string;
224
- } | undefined): (collection: string) => Promise<{
225
- id: string;
226
- } | undefined>;
194
+ /** Reads the collection's own connection data, at the installation's address. */
195
+ protected requestOrganizationUserId(session: ProviderAuthenticationSession, collection: string): Promise<string | undefined>;
227
196
  /** Every collection the account can see, or a refusal when discovery itself failed. */
228
197
  private getSearchCollections;
229
198
  /**
@@ -10,9 +10,10 @@ import "../constants.js";
10
10
  import { toCollectionScopeFailure } from "../collectionMetadata.js";
11
11
  import { toTokenWithInfo } from "../authentication/models.js";
12
12
  import { compareAzurePullRequestSearchPositions, getInvalidAzureSearchDate, isAzureWorkItemSearchFirstPage, parseAzurePullRequestSearchCursor, toAzurePullRequestSearchCursorKey, toAzurePullRequestSearchFilter, toAzurePullRequestSearchPosition, toAzureSearchPageSize } from "./azure/search.js";
13
- import { fromProviderPullRequest, getProviderPullRequestIdentity, isNativePullRequest, providersMetadata, toProviderPullRequestStates } from "./models.js";
13
+ import { fromProviderPullRequest, getProviderPullRequestIdentity, providersMetadata, toProviderPullRequestStates } from "./models.js";
14
+ import { getAzureRepositoryIdentity } from "./azure/azure.utils.js";
14
15
  import { discoveryCacheTtl } from "./utils/discoveryCache.js";
15
- import { AzureDevOpsIntegrationBase, findAzureRepositoryApiBaseUrl, getAzureRepositoryApiBaseUrl, getAzureRepositoryIdentity, getAzureScopeVirtualDirectory, isAzureProjectlessCandidate, markMyGroupReviews, resolveAzureProjectlessRepository, sameAzureName, toAzureReviewerReads, uniqueAzureNames } from "./azureDevOps.js";
16
+ import { AzureDevOpsIntegrationBase, findAzureRepositoryApiBaseUrl, getAzureRepositoryApiBaseUrl, getAzureScopeVirtualDirectory, isAzureProjectlessCandidate, markMyGroupReviews, resolveAzureProjectlessRepository, sameAzureName, toAzureReviewerReads, uniqueAzureNames } from "./azureDevOps.js";
16
17
  //#region ../plus/integrations/src/providers/azureDevOpsServer.ts
17
18
  /**
18
19
  * Whether `value` can stand as one route segment. Encoding keeps `.` and `..` as they are, and a URL resolves them
@@ -149,7 +150,8 @@ var AzureDevOpsServerIntegration = class extends AzureDevOpsIntegrationBase {
149
150
  });
150
151
  }
151
152
  /**
152
- * The collection names per credential and installation, `undefined` when they couldn't be read. Only a
153
+ * The collection names per credential and installation, `undefined` when they couldn't be read, and whether the
154
+ * address is then presumed to name a collection ({@link requestResourcesForUser}). Only a
153
155
  * tie-breaker for {@link getRepositoryTarget}, so a failed read is kept (for {@link discoveryCacheTtl}) rather than
154
156
  * retried on every repository read; a successful one comes from the organizations, which are kept for the session.
155
157
  */
@@ -157,6 +159,8 @@ var AzureDevOpsServerIntegration = class extends AzureDevOpsIntegrationBase {
157
159
  capacity: 10,
158
160
  createTTL: discoveryCacheTtl
159
161
  });
162
+ /** The failures to read the collection an address names after its collection list answered with a 404. */
163
+ _collectionListRefusals = /* @__PURE__ */ new WeakSet();
160
164
  /**
161
165
  * Settles which segment of a remote's path is the collection before reading the repository. Behind a virtual
162
166
  * directory a repository named after its project is also served as `{vdir}/{collection}/_git/{repo}`, which the
@@ -176,15 +180,18 @@ var AzureDevOpsServerIntegration = class extends AzureDevOpsIntegrationBase {
176
180
  /**
177
181
  * The repository {@link getRepositoryTarget} reads `repo` as, and the base it reads it below: `undefined` when the
178
182
  * connection doesn't serve its virtual directory (another installation's) or that directory isn't a valid one.
183
+ * `isCandidate` is whether `repo` can be project-less below the connection ({@link isAzureProjectlessCandidate} by
184
+ * default), given whether the connection is known to address a collection rather than the installation.
179
185
  */
180
- async settleRepository(session, repo, cancellation) {
186
+ async settleRepository(session, repo, cancellation, isCandidate) {
181
187
  const baseUrl = this.apiBaseUrlFor(session);
188
+ const candidate = isCandidate ?? ((belowCollection) => isAzureProjectlessCandidate(baseUrl, repo, belowCollection));
182
189
  let unsettled = false;
183
- if (isAzureProjectlessCandidate(baseUrl, repo)) {
184
- const names = this._collectionNames.getOrCreate(this.discoveryKey(session), () => this.getCollectionNames(session));
185
- const collections = await (cancellation != null ? raceWithSignal(names, cancellation) : names);
186
- if (collections != null) repo = resolveAzureProjectlessRepository(repo, collections);
187
- else unsettled = true;
190
+ if (candidate(false)) {
191
+ const discovery = this._collectionNames.getOrCreate(this.discoveryKey(session), () => this.getCollectionNames(session));
192
+ const { names, addressesCollection } = await (cancellation != null ? raceWithSignal(discovery, cancellation) : discovery);
193
+ if (names != null) repo = resolveAzureProjectlessRepository(repo, names);
194
+ else unsettled = candidate(addressesCollection === true);
188
195
  }
189
196
  return {
190
197
  repo,
@@ -212,14 +219,21 @@ var AzureDevOpsServerIntegration = class extends AzureDevOpsIntegrationBase {
212
219
  name: `${c.project}/_git/${c.repo}`,
213
220
  project: c.project,
214
221
  virtualDirectory: virtualDirectory || void 0
215
- }, cancellation);
216
- return {
217
- coordinate: repo.owner !== c.owner && repoBaseUrl != null ? {
222
+ }, cancellation, (belowCollection) => getAzureScopeVirtualDirectory(baseUrl, c.owner, belowCollection) != null);
223
+ if (repo.owner === c.owner) return {
224
+ coordinate: c,
225
+ unsettled
226
+ };
227
+ return repoBaseUrl != null ? {
228
+ coordinate: {
218
229
  ...c,
219
230
  owner: repo.owner,
220
231
  project: repo.project
221
- } : c,
232
+ },
222
233
  unsettled
234
+ } : {
235
+ coordinate: c,
236
+ unsettled: true
223
237
  };
224
238
  }));
225
239
  return {
@@ -228,37 +242,20 @@ var AzureDevOpsServerIntegration = class extends AzureDevOpsIntegrationBase {
228
242
  };
229
243
  }
230
244
  /**
231
- * The searches and counts take only `repos`: they re-read the collections and refuse a scope whose collection
232
- * isn't one of them ({@link getSearchCollections}), and a scope read as parsed below a listed collection is what
233
- * settling it would read ({@link resolveAzureProjectlessRepository}), so a miss there is not `unsettled`.
234
- */
235
- async resolveRepositoryInputs(session, repos, cancellation) {
236
- const { coordinates, unsettled } = await this.resolveRepositoryCoordinates(session, repos.map((r) => ({
237
- ...r,
238
- owner: r.namespace,
239
- repo: r.name
240
- })), cancellation);
241
- return {
242
- repos: coordinates.map(({ owner, repo, ...r }) => ({
243
- ...r,
244
- namespace: owner,
245
- name: repo
246
- })),
247
- unsettled
248
- };
249
- }
250
- /**
251
245
  * Never rejects. A credential refused the list leaves every path as parsed, as before discovery was asked; any other
252
246
  * failure is `undefined`, so a read of a path it could have settled keeps a miss out of the caches (see
253
247
  * `readRepository`).
254
248
  */
255
249
  async getCollectionNames(session) {
256
250
  try {
257
- return (await this.getProviderResourcesForUser(session))?.map((r) => r.name);
251
+ return { names: (await this.getProviderResourcesForUser(session))?.map((r) => r.name) };
258
252
  } catch (ex) {
259
- if (ex instanceof AuthenticationError) return [];
253
+ if (ex instanceof AuthenticationError) return { names: [] };
260
254
  _logger.debug(`${this.name}: collections at ${this.apiBaseUrlFor(session)} couldn't be read to place a repository path`, ex);
261
- return;
255
+ return {
256
+ names: void 0,
257
+ addressesCollection: this._collectionListRefusals.has(ex)
258
+ };
262
259
  }
263
260
  }
264
261
  invalidateDiscoveryCaches() {
@@ -268,20 +265,29 @@ var AzureDevOpsServerIntegration = class extends AzureDevOpsIntegrationBase {
268
265
  /**
269
266
  * Only the server level lists the collections: below one, Azure DevOps Server answers `projectCollections` with a
270
267
  * 404 page. On that 404 an address that names a collection reads the collection's own connection data, whose
271
- * `webApplicationRelativeDirectory` spells it, and reports it as the one collection visible there.
268
+ * `webApplicationRelativeDirectory` spells it, and reports it as the one collection visible there. When that read
269
+ * fails, the address is presumed to name a collection, which the failure carries (see {@link getCollectionNames}) for
270
+ * as long as the failed discovery is kept; connection data that answers for the server says it doesn't.
272
271
  */
273
272
  async requestResourcesForUser(session, userId) {
274
273
  try {
275
274
  return await super.requestResourcesForUser(session, userId);
276
275
  } catch (ex) {
277
276
  if (!(ex instanceof RequestNotFoundError)) throw ex;
278
- const addressed = await (await this.authenticationService.apis.azure)?.getAddressedCollection(this, toTokenWithInfo(this.id, session), this.apiBaseUrlFor(session));
277
+ const azure = await this.authenticationService.apis.azure;
278
+ let addressed;
279
+ try {
280
+ addressed = await azure?.getAddressedCollection(this, toTokenWithInfo(this.id, session), this.apiBaseUrlFor(session));
281
+ } catch (collectionError) {
282
+ if (typeof collectionError === "object" && collectionError != null) this._collectionListRefusals.add(collectionError);
283
+ throw collectionError;
284
+ }
279
285
  if (addressed == null) throw ex;
280
286
  return [addressed];
281
287
  }
282
288
  }
283
289
  /**
284
- * The filtered work-item search: one WIQL query per page over ONE collection, then one detail read for the
290
+ * The filtered work-item search snapshots matching ids with bounded WIQL queries, then reads details for each
285
291
  * page's slice. See {@link resolveWorkItemSearchScope} for why a search never spans several collections.
286
292
  */
287
293
  async searchProviderIssuesPage(session, options, cancellation) {
@@ -294,6 +300,7 @@ var AzureDevOpsServerIntegration = class extends AzureDevOpsIntegrationBase {
294
300
  baseUrl: this.collectionApiBaseUrl(session, scope.collection),
295
301
  criteria: options.criteria,
296
302
  projectNames: scope.projectNames,
303
+ workflowProjectNames: scope.projects.map((p) => p.name),
297
304
  resolveProject: (name) => scope.projects.find((p) => sameAzureName(p.name, name)),
298
305
  cursor: options.cursor,
299
306
  pageSize: options.pageSize
@@ -316,7 +323,8 @@ var AzureDevOpsServerIntegration = class extends AzureDevOpsIntegrationBase {
316
323
  return azure.countWorkItems(this, tokenWithInfo, scope.collection, {
317
324
  baseUrl: this.collectionApiBaseUrl(session, scope.collection),
318
325
  criteria: s.criteria,
319
- projectNames: scope.projectNames
326
+ projectNames: scope.projectNames,
327
+ workflowProjectNames: scope.projects.map((p) => p.name)
320
328
  }, cancellation);
321
329
  }));
322
330
  }
@@ -625,55 +633,9 @@ var AzureDevOpsServerIntegration = class extends AzureDevOpsIntegrationBase {
625
633
  project: p
626
634
  }));
627
635
  }
628
- _collectionUserIds = new PromiseCache({ capacity: 50 });
629
- /**
630
- * The current user's identity id in `collection`, read from the collection's own connection data, which is
631
- * what Azure's creator and reviewer filters compare against. Cached per credential and collection, since it
632
- * can't change for either.
633
- */
634
- getFilterUserId(session, collection) {
635
- const baseUrl = this.collectionApiBaseUrl(session, collection);
636
- return this._collectionUserIds.getOrCreate(JSON.stringify([
637
- session.accessToken,
638
- baseUrl,
639
- collection.toLowerCase()
640
- ]), async (cacheable) => {
641
- const user = await (await this.authenticationService.apis.azure)?.getCurrentUserOnServer(this, toTokenWithInfo(this.id, session), `${baseUrl}/${encodeURIComponent(collection)}`);
642
- if (user?.id == null) cacheable.invalidate();
643
- return user?.id;
644
- });
645
- }
646
- /**
647
- * Resolved per collection, which a raw row names as its repository owner: a collection's pull requests carry the
648
- * id {@link getFilterUserId} resolves there, never the server-level account's. A row that names no collection or
649
- * has no author to match gets no viewer, nor does one in a collection whose id can't be read: its authorship
650
- * stays unknown.
651
- */
652
- async getPullRequestViewers(pullRequests, connectionId) {
653
- const session = await this.resolveReadSessionOrThrow(connectionId, void 0);
654
- if (session == null) return pullRequests.map(() => void 0);
655
- const viewerFor = this.getOrganizationViewers(session, void 0);
656
- return Promise.all(pullRequests.map((pr) => {
657
- const collection = isNativePullRequest(pr) ? void 0 : pr.repository?.owner?.login;
658
- return collection && pr.author != null ? viewerFor(collection) : Promise.resolve(void 0);
659
- }));
660
- }
661
- /**
662
- * Ignores `account`: it is the server-level one, which no collection's pull requests carry. A collection whose id
663
- * can't be read resolves `undefined`, since authorship is optional enrichment and one collection's failed lookup
664
- * must not fail the read or blank the others; it is asked once per read, as a miss isn't cached.
665
- */
666
- getOrganizationViewers(session, _account) {
667
- const viewers = /* @__PURE__ */ new Map();
668
- return (collection) => {
669
- const key = collection.toLowerCase();
670
- let viewer = viewers.get(key);
671
- if (viewer == null) {
672
- viewer = this.getFilterUserId(session, collection).then((id) => id != null ? { id } : void 0, () => void 0);
673
- viewers.set(key, viewer);
674
- }
675
- return viewer;
676
- };
636
+ /** Reads the collection's own connection data, at the installation's address. */
637
+ async requestOrganizationUserId(session, collection) {
638
+ return (await (await this.authenticationService.apis.azure)?.getCurrentUserOnServer(this, toTokenWithInfo(this.id, session), `${this.collectionApiBaseUrl(session, collection)}/${encodeURIComponent(collection)}`))?.id;
677
639
  }
678
640
  /** Every collection the account can see, or a refusal when discovery itself failed. */
679
641
  async getSearchCollections(session) {
@@ -723,7 +685,6 @@ var AzureDevOpsServerIntegration = class extends AzureDevOpsIntegrationBase {
723
685
  super.providerOnDisconnect();
724
686
  this._pullRequestSearches.clear();
725
687
  this._latestPullRequestSearches.clear();
726
- this._collectionUserIds.clear();
727
688
  this._collectionNames.clear();
728
689
  }
729
690
  async _requestForCurrentUser(session) {