@backstage/plugin-scaffolder-common 1.6.0 → 1.7.0-next.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/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @backstage/plugin-scaffolder-common
2
2
 
3
+ ## 1.7.0-next.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c08cbc4: Move Scaffolder API to OpenAPI
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @backstage/catalog-model@1.7.5
13
+ - @backstage/errors@1.2.7
14
+ - @backstage/integration@1.17.1
15
+ - @backstage/types@1.2.1
16
+ - @backstage/plugin-permission-common@0.9.1
17
+
3
18
  ## 1.6.0
4
19
 
5
20
  ### Minor Changes
@@ -0,0 +1,284 @@
1
+ 'use strict';
2
+
3
+ var catalogModel = require('@backstage/catalog-model');
4
+ var errors = require('@backstage/errors');
5
+ var fetchEventSource = require('@microsoft/fetch-event-source');
6
+ var ObservableImpl = require('zen-observable');
7
+ var Api_client = require('./schema/openapi/generated/apis/Api.client.cjs.js');
8
+
9
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
10
+
11
+ var ObservableImpl__default = /*#__PURE__*/_interopDefaultCompat(ObservableImpl);
12
+
13
+ class ScaffolderClient {
14
+ apiClient;
15
+ discoveryApi;
16
+ scmIntegrationsApi;
17
+ fetchApi;
18
+ identityApi;
19
+ useLongPollingLogs;
20
+ constructor(options) {
21
+ this.apiClient = new Api_client.DefaultApiClient(options);
22
+ this.discoveryApi = options.discoveryApi;
23
+ this.fetchApi = options.fetchApi ?? { fetch };
24
+ this.scmIntegrationsApi = options.scmIntegrationsApi;
25
+ this.useLongPollingLogs = options.useLongPollingLogs ?? false;
26
+ this.identityApi = options.identityApi;
27
+ }
28
+ /**
29
+ * {@inheritdoc ScaffolderApi.listTasks}
30
+ */
31
+ async listTasks(request, options) {
32
+ if (!this.identityApi) {
33
+ throw new Error(
34
+ "IdentityApi is not available in the ScaffolderClient, please pass through the IdentityApi to the ScaffolderClient constructor in order to use the listTasks method"
35
+ );
36
+ }
37
+ const { userEntityRef } = await this.identityApi.getBackstageIdentity();
38
+ return await this.requestRequired(
39
+ await this.apiClient.listTasks(
40
+ {
41
+ query: {
42
+ createdBy: request.filterByOwnership === "owned" ? [userEntityRef] : void 0,
43
+ limit: request.limit,
44
+ offset: request.offset
45
+ }
46
+ },
47
+ options
48
+ )
49
+ );
50
+ }
51
+ async getIntegrationsList(options) {
52
+ const integrations = [
53
+ ...this.scmIntegrationsApi.azure.list(),
54
+ ...this.scmIntegrationsApi.bitbucket.list().filter(
55
+ (item) => !this.scmIntegrationsApi.bitbucketCloud.byHost(item.config.host) && !this.scmIntegrationsApi.bitbucketServer.byHost(item.config.host)
56
+ ),
57
+ ...this.scmIntegrationsApi.bitbucketCloud.list(),
58
+ ...this.scmIntegrationsApi.bitbucketServer.list(),
59
+ ...this.scmIntegrationsApi.gerrit.list(),
60
+ ...this.scmIntegrationsApi.gitea.list(),
61
+ ...this.scmIntegrationsApi.github.list(),
62
+ ...this.scmIntegrationsApi.gitlab.list()
63
+ ].map((c) => ({ type: c.type, title: c.title, host: c.config.host })).filter((c) => options.allowedHosts.includes(c.host));
64
+ return {
65
+ integrations
66
+ };
67
+ }
68
+ /**
69
+ * {@inheritdoc ScaffolderApi.getTemplateParameterSchema}
70
+ */
71
+ async getTemplateParameterSchema(templateRef, options) {
72
+ return await this.requestRequired(
73
+ await this.apiClient.getTemplateParameterSchema(
74
+ {
75
+ path: catalogModel.parseEntityRef(templateRef, {
76
+ defaultKind: "template"
77
+ })
78
+ },
79
+ options
80
+ )
81
+ );
82
+ }
83
+ /**
84
+ * {@inheritdoc ScaffolderApi.scaffold}
85
+ */
86
+ async scaffold(request, options) {
87
+ const response = await this.apiClient.scaffold(
88
+ {
89
+ body: request
90
+ },
91
+ options
92
+ );
93
+ if (response.status !== 201) {
94
+ const status = `${response.status} ${response.statusText}`;
95
+ const body = await response.text();
96
+ throw new Error(`Backend request failed, ${status} ${body.trim()}`);
97
+ }
98
+ const { id } = await response.json();
99
+ return { taskId: id };
100
+ }
101
+ /**
102
+ * {@inheritdoc ScaffolderApi.getTask}
103
+ */
104
+ async getTask(taskId, options) {
105
+ return await this.requestRequired(
106
+ await this.apiClient.getTask(
107
+ {
108
+ path: { taskId }
109
+ },
110
+ options
111
+ )
112
+ );
113
+ }
114
+ /**
115
+ * {@inheritdoc ScaffolderApi.streamLogs}
116
+ */
117
+ streamLogs(request, options) {
118
+ if (this.useLongPollingLogs) {
119
+ return this.streamLogsPolling(request, options);
120
+ }
121
+ return this.streamLogsEventStream(request);
122
+ }
123
+ /**
124
+ * {@inheritdoc ScaffolderApi.dryRun}
125
+ */
126
+ async dryRun(request, options) {
127
+ return await this.requestRequired(
128
+ await this.apiClient.dryRun(
129
+ {
130
+ body: {
131
+ template: request.template,
132
+ values: request.values,
133
+ secrets: request.secrets,
134
+ directoryContents: request.directoryContents
135
+ }
136
+ },
137
+ options
138
+ )
139
+ );
140
+ }
141
+ streamLogsEventStream({
142
+ isTaskRecoverable,
143
+ taskId,
144
+ after
145
+ }) {
146
+ return new ObservableImpl__default.default((subscriber) => {
147
+ const params = new URLSearchParams();
148
+ if (after !== void 0) {
149
+ params.set("after", String(Number(after)));
150
+ }
151
+ this.discoveryApi.getBaseUrl("scaffolder").then(
152
+ (baseUrl) => {
153
+ const url = `${baseUrl}/v2/tasks/${encodeURIComponent(
154
+ taskId
155
+ )}/eventstream`;
156
+ const processEvent = (event) => {
157
+ if (event.data) {
158
+ try {
159
+ subscriber.next(JSON.parse(event.data));
160
+ } catch (ex) {
161
+ subscriber.error(ex);
162
+ }
163
+ }
164
+ };
165
+ const ctrl = new AbortController();
166
+ void fetchEventSource.fetchEventSource(url, {
167
+ fetch: this.fetchApi.fetch,
168
+ signal: ctrl.signal,
169
+ onmessage(e) {
170
+ if (e.event === "log") {
171
+ processEvent(e);
172
+ return;
173
+ } else if (e.event === "completion" && !isTaskRecoverable) {
174
+ processEvent(e);
175
+ subscriber.complete();
176
+ ctrl.abort();
177
+ return;
178
+ }
179
+ processEvent(e);
180
+ },
181
+ onerror(err) {
182
+ subscriber.error(err);
183
+ }
184
+ });
185
+ },
186
+ (error) => {
187
+ subscriber.error(error);
188
+ }
189
+ );
190
+ });
191
+ }
192
+ streamLogsPolling({
193
+ taskId,
194
+ after: inputAfter
195
+ }, options) {
196
+ let after = inputAfter;
197
+ return new ObservableImpl__default.default((subscriber) => {
198
+ (async () => {
199
+ while (!subscriber.closed) {
200
+ const response = await this.apiClient.streamLogsPolling(
201
+ {
202
+ path: { taskId },
203
+ query: { after }
204
+ },
205
+ options
206
+ );
207
+ if (!response.ok) {
208
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
209
+ continue;
210
+ }
211
+ const logs = await response.json();
212
+ for (const event of logs) {
213
+ after = Number(event.id);
214
+ subscriber.next(event);
215
+ if (event.type === "completion") {
216
+ subscriber.complete();
217
+ return;
218
+ }
219
+ }
220
+ }
221
+ })();
222
+ });
223
+ }
224
+ /**
225
+ * {@inheritdoc ScaffolderApi.listActions}
226
+ */
227
+ async listActions(options) {
228
+ return await this.requestRequired(
229
+ await this.apiClient.listActions(null, options)
230
+ );
231
+ }
232
+ /**
233
+ * {@inheritdoc ScaffolderApi.listTemplatingExtensions}
234
+ */
235
+ async listTemplatingExtensions(options) {
236
+ return await this.requestRequired(
237
+ await this.apiClient.listTemplatingExtensions(null, options)
238
+ );
239
+ }
240
+ /**
241
+ * {@inheritdoc ScaffolderApi.cancelTask}
242
+ */
243
+ async cancelTask(taskId, options) {
244
+ return await this.requestRequired(
245
+ await this.apiClient.cancelTask({ path: { taskId } }, options)
246
+ );
247
+ }
248
+ /**
249
+ * {@inheritdoc ScaffolderApi.retry}
250
+ */
251
+ async retry(taskId, options) {
252
+ return await this.requestRequired(
253
+ await this.apiClient.retry({ body: {}, path: { taskId } }, options)
254
+ );
255
+ }
256
+ /**
257
+ * {@inheritdoc ScaffolderApi.retry}
258
+ */
259
+ async autocomplete({
260
+ token,
261
+ resource,
262
+ provider,
263
+ context
264
+ }) {
265
+ return await this.requestRequired(
266
+ await this.apiClient.autocomplete({
267
+ path: { provider, resource },
268
+ body: { token, context }
269
+ })
270
+ );
271
+ }
272
+ //
273
+ // Private methods
274
+ //
275
+ async requestRequired(response) {
276
+ if (!response.ok) {
277
+ throw await errors.ResponseError.fromResponse(response);
278
+ }
279
+ return response.json();
280
+ }
281
+ }
282
+
283
+ exports.ScaffolderClient = ScaffolderClient;
284
+ //# sourceMappingURL=ScaffolderClient.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScaffolderClient.cjs.js","sources":["../src/ScaffolderClient.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { parseEntityRef } from '@backstage/catalog-model';\nimport { ResponseError } from '@backstage/errors';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport { Observable } from '@backstage/types';\nimport {\n EventSourceMessage,\n fetchEventSource,\n} from '@microsoft/fetch-event-source';\nimport ObservableImpl from 'zen-observable';\n\nimport { type TemplateParameterSchema } from './TemplateEntityV1beta3';\nimport {\n ListActionsResponse,\n ListTemplatingExtensionsResponse,\n LogEvent,\n ScaffolderApi,\n ScaffolderDryRunOptions,\n ScaffolderDryRunResponse,\n ScaffolderGetIntegrationsListOptions,\n ScaffolderGetIntegrationsListResponse,\n ScaffolderRequestOptions,\n ScaffolderScaffoldOptions,\n ScaffolderScaffoldResponse,\n ScaffolderStreamLogsOptions,\n ScaffolderTask,\n} from './api';\nimport { DefaultApiClient, TaskStatus, TypedResponse } from './schema/openapi';\n\n/**\n * An API to interact with the scaffolder backend.\n *\n * @public\n */\nexport class ScaffolderClient implements ScaffolderApi {\n private readonly apiClient: DefaultApiClient;\n private readonly discoveryApi: {\n getBaseUrl(pluginId: string): Promise<string>;\n };\n private readonly scmIntegrationsApi: ScmIntegrationRegistry;\n private readonly fetchApi: { fetch: typeof fetch };\n private readonly identityApi?: {\n getBackstageIdentity(): Promise<{\n type: 'user';\n userEntityRef: string;\n ownershipEntityRefs: string[];\n }>;\n };\n private readonly useLongPollingLogs: boolean;\n\n constructor(options: {\n discoveryApi: { getBaseUrl(pluginId: string): Promise<string> };\n fetchApi: { fetch: typeof fetch };\n identityApi?: {\n getBackstageIdentity(): Promise<{\n type: 'user';\n userEntityRef: string;\n ownershipEntityRefs: string[];\n }>;\n };\n scmIntegrationsApi: ScmIntegrationRegistry;\n useLongPollingLogs?: boolean;\n }) {\n this.apiClient = new DefaultApiClient(options);\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi ?? { fetch };\n this.scmIntegrationsApi = options.scmIntegrationsApi;\n this.useLongPollingLogs = options.useLongPollingLogs ?? false;\n this.identityApi = options.identityApi;\n }\n\n /**\n * {@inheritdoc ScaffolderApi.listTasks}\n */\n async listTasks(\n request: {\n filterByOwnership: 'owned' | 'all';\n limit?: number;\n offset?: number;\n },\n options?: ScaffolderRequestOptions,\n ): Promise<{ tasks: ScaffolderTask[]; totalTasks?: number }> {\n if (!this.identityApi) {\n throw new Error(\n 'IdentityApi is not available in the ScaffolderClient, please pass through the IdentityApi to the ScaffolderClient constructor in order to use the listTasks method',\n );\n }\n\n const { userEntityRef } = await this.identityApi.getBackstageIdentity();\n\n return await this.requestRequired(\n await this.apiClient.listTasks(\n {\n query: {\n createdBy:\n request.filterByOwnership === 'owned'\n ? [userEntityRef]\n : undefined,\n limit: request.limit,\n offset: request.offset,\n },\n },\n options,\n ),\n );\n }\n\n async getIntegrationsList(\n options: ScaffolderGetIntegrationsListOptions,\n ): Promise<ScaffolderGetIntegrationsListResponse> {\n const integrations = [\n ...this.scmIntegrationsApi.azure.list(),\n ...this.scmIntegrationsApi.bitbucket\n .list()\n .filter(\n item =>\n !this.scmIntegrationsApi.bitbucketCloud.byHost(item.config.host) &&\n !this.scmIntegrationsApi.bitbucketServer.byHost(item.config.host),\n ),\n ...this.scmIntegrationsApi.bitbucketCloud.list(),\n ...this.scmIntegrationsApi.bitbucketServer.list(),\n ...this.scmIntegrationsApi.gerrit.list(),\n ...this.scmIntegrationsApi.gitea.list(),\n ...this.scmIntegrationsApi.github.list(),\n ...this.scmIntegrationsApi.gitlab.list(),\n ]\n .map(c => ({ type: c.type, title: c.title, host: c.config.host }))\n .filter(c => options.allowedHosts.includes(c.host));\n\n return {\n integrations,\n };\n }\n\n /**\n * {@inheritdoc ScaffolderApi.getTemplateParameterSchema}\n */\n async getTemplateParameterSchema(\n templateRef: string,\n options?: ScaffolderRequestOptions,\n ): Promise<TemplateParameterSchema> {\n return await this.requestRequired(\n await this.apiClient.getTemplateParameterSchema(\n {\n path: parseEntityRef(templateRef, {\n defaultKind: 'template',\n }),\n },\n options,\n ),\n );\n }\n\n /**\n * {@inheritdoc ScaffolderApi.scaffold}\n */\n async scaffold(\n request: ScaffolderScaffoldOptions,\n options?: ScaffolderRequestOptions,\n ): Promise<ScaffolderScaffoldResponse> {\n const response = await this.apiClient.scaffold(\n {\n body: request,\n },\n options,\n );\n\n if (response.status !== 201) {\n const status = `${response.status} ${response.statusText}`;\n const body = await response.text();\n throw new Error(`Backend request failed, ${status} ${body.trim()}`);\n }\n\n const { id } = await response.json();\n return { taskId: id };\n }\n\n /**\n * {@inheritdoc ScaffolderApi.getTask}\n */\n async getTask(\n taskId: string,\n options?: ScaffolderRequestOptions,\n ): Promise<ScaffolderTask> {\n return await this.requestRequired(\n await this.apiClient.getTask(\n {\n path: { taskId },\n },\n options,\n ),\n );\n }\n\n /**\n * {@inheritdoc ScaffolderApi.streamLogs}\n */\n streamLogs(\n request: ScaffolderStreamLogsOptions,\n options?: ScaffolderRequestOptions,\n ): Observable<LogEvent> {\n if (this.useLongPollingLogs) {\n return this.streamLogsPolling(request, options);\n }\n\n return this.streamLogsEventStream(request);\n }\n\n /**\n * {@inheritdoc ScaffolderApi.dryRun}\n */\n async dryRun(\n request: ScaffolderDryRunOptions,\n options?: ScaffolderRequestOptions,\n ): Promise<ScaffolderDryRunResponse> {\n return await this.requestRequired(\n await this.apiClient.dryRun(\n {\n body: {\n template: request.template,\n values: request.values,\n secrets: request.secrets,\n directoryContents: request.directoryContents,\n },\n },\n options,\n ),\n );\n }\n\n private streamLogsEventStream({\n isTaskRecoverable,\n taskId,\n after,\n }: ScaffolderStreamLogsOptions): Observable<LogEvent> {\n return new ObservableImpl(subscriber => {\n const params = new URLSearchParams();\n if (after !== undefined) {\n params.set('after', String(Number(after)));\n }\n\n this.discoveryApi.getBaseUrl('scaffolder').then(\n baseUrl => {\n const url = `${baseUrl}/v2/tasks/${encodeURIComponent(\n taskId,\n )}/eventstream`;\n\n const processEvent = (event: any) => {\n if (event.data) {\n try {\n subscriber.next(JSON.parse(event.data));\n } catch (ex) {\n subscriber.error(ex);\n }\n }\n };\n\n const ctrl = new AbortController();\n void fetchEventSource(url, {\n fetch: this.fetchApi.fetch,\n signal: ctrl.signal,\n onmessage(e: EventSourceMessage) {\n if (e.event === 'log') {\n processEvent(e);\n return;\n } else if (e.event === 'completion' && !isTaskRecoverable) {\n processEvent(e);\n subscriber.complete();\n ctrl.abort();\n return;\n }\n processEvent(e);\n },\n onerror(err) {\n subscriber.error(err);\n },\n });\n },\n error => {\n subscriber.error(error);\n },\n );\n });\n }\n\n private streamLogsPolling(\n {\n taskId,\n after: inputAfter,\n }: {\n taskId: string;\n after?: number;\n },\n options?: ScaffolderRequestOptions,\n ): Observable<LogEvent> {\n let after = inputAfter;\n\n return new ObservableImpl(subscriber => {\n (async () => {\n while (!subscriber.closed) {\n const response = await this.apiClient.streamLogsPolling(\n {\n path: { taskId },\n query: { after },\n },\n options,\n );\n\n if (!response.ok) {\n // wait for one second to not run into an\n await new Promise(resolve => setTimeout(resolve, 1000));\n continue;\n }\n\n const logs = (await response.json()) as LogEvent[];\n\n for (const event of logs) {\n after = Number(event.id);\n\n subscriber.next(event);\n\n if (event.type === 'completion') {\n subscriber.complete();\n return;\n }\n }\n }\n })();\n });\n }\n\n /**\n * {@inheritdoc ScaffolderApi.listActions}\n */\n async listActions(\n options?: ScaffolderRequestOptions,\n ): Promise<ListActionsResponse> {\n return await this.requestRequired(\n await this.apiClient.listActions(null as any, options),\n );\n }\n\n /**\n * {@inheritdoc ScaffolderApi.listTemplatingExtensions}\n */\n async listTemplatingExtensions(\n options?: ScaffolderRequestOptions,\n ): Promise<ListTemplatingExtensionsResponse> {\n return await this.requestRequired(\n await this.apiClient.listTemplatingExtensions(null as any, options),\n );\n }\n\n /**\n * {@inheritdoc ScaffolderApi.cancelTask}\n */\n async cancelTask(\n taskId: string,\n options?: ScaffolderRequestOptions,\n ): Promise<{ status?: TaskStatus }> {\n return await this.requestRequired(\n await this.apiClient.cancelTask({ path: { taskId } }, options),\n );\n }\n\n /**\n * {@inheritdoc ScaffolderApi.retry}\n */\n async retry?(\n taskId: string,\n options?: ScaffolderRequestOptions,\n ): Promise<{ id: string }> {\n return await this.requestRequired(\n await this.apiClient.retry({ body: {}, path: { taskId } }, options),\n );\n }\n\n /**\n * {@inheritdoc ScaffolderApi.retry}\n */\n async autocomplete({\n token,\n resource,\n provider,\n context,\n }: {\n token: string;\n provider: string;\n resource: string;\n context: Record<string, string>;\n }): Promise<{ results: { title?: string; id: string }[] }> {\n return await this.requestRequired(\n await this.apiClient.autocomplete({\n path: { provider, resource },\n body: { token, context },\n }),\n );\n }\n\n //\n // Private methods\n //\n\n private async requestRequired<T>(response: TypedResponse<T>): Promise<T> {\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return response.json();\n }\n}\n"],"names":["DefaultApiClient","parseEntityRef","ObservableImpl","fetchEventSource","ResponseError"],"mappings":"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"}
@@ -0,0 +1,278 @@
1
+ import { parseEntityRef } from '@backstage/catalog-model';
2
+ import { ResponseError } from '@backstage/errors';
3
+ import { fetchEventSource } from '@microsoft/fetch-event-source';
4
+ import ObservableImpl from 'zen-observable';
5
+ import { DefaultApiClient } from './schema/openapi/generated/apis/Api.client.esm.js';
6
+
7
+ class ScaffolderClient {
8
+ apiClient;
9
+ discoveryApi;
10
+ scmIntegrationsApi;
11
+ fetchApi;
12
+ identityApi;
13
+ useLongPollingLogs;
14
+ constructor(options) {
15
+ this.apiClient = new DefaultApiClient(options);
16
+ this.discoveryApi = options.discoveryApi;
17
+ this.fetchApi = options.fetchApi ?? { fetch };
18
+ this.scmIntegrationsApi = options.scmIntegrationsApi;
19
+ this.useLongPollingLogs = options.useLongPollingLogs ?? false;
20
+ this.identityApi = options.identityApi;
21
+ }
22
+ /**
23
+ * {@inheritdoc ScaffolderApi.listTasks}
24
+ */
25
+ async listTasks(request, options) {
26
+ if (!this.identityApi) {
27
+ throw new Error(
28
+ "IdentityApi is not available in the ScaffolderClient, please pass through the IdentityApi to the ScaffolderClient constructor in order to use the listTasks method"
29
+ );
30
+ }
31
+ const { userEntityRef } = await this.identityApi.getBackstageIdentity();
32
+ return await this.requestRequired(
33
+ await this.apiClient.listTasks(
34
+ {
35
+ query: {
36
+ createdBy: request.filterByOwnership === "owned" ? [userEntityRef] : void 0,
37
+ limit: request.limit,
38
+ offset: request.offset
39
+ }
40
+ },
41
+ options
42
+ )
43
+ );
44
+ }
45
+ async getIntegrationsList(options) {
46
+ const integrations = [
47
+ ...this.scmIntegrationsApi.azure.list(),
48
+ ...this.scmIntegrationsApi.bitbucket.list().filter(
49
+ (item) => !this.scmIntegrationsApi.bitbucketCloud.byHost(item.config.host) && !this.scmIntegrationsApi.bitbucketServer.byHost(item.config.host)
50
+ ),
51
+ ...this.scmIntegrationsApi.bitbucketCloud.list(),
52
+ ...this.scmIntegrationsApi.bitbucketServer.list(),
53
+ ...this.scmIntegrationsApi.gerrit.list(),
54
+ ...this.scmIntegrationsApi.gitea.list(),
55
+ ...this.scmIntegrationsApi.github.list(),
56
+ ...this.scmIntegrationsApi.gitlab.list()
57
+ ].map((c) => ({ type: c.type, title: c.title, host: c.config.host })).filter((c) => options.allowedHosts.includes(c.host));
58
+ return {
59
+ integrations
60
+ };
61
+ }
62
+ /**
63
+ * {@inheritdoc ScaffolderApi.getTemplateParameterSchema}
64
+ */
65
+ async getTemplateParameterSchema(templateRef, options) {
66
+ return await this.requestRequired(
67
+ await this.apiClient.getTemplateParameterSchema(
68
+ {
69
+ path: parseEntityRef(templateRef, {
70
+ defaultKind: "template"
71
+ })
72
+ },
73
+ options
74
+ )
75
+ );
76
+ }
77
+ /**
78
+ * {@inheritdoc ScaffolderApi.scaffold}
79
+ */
80
+ async scaffold(request, options) {
81
+ const response = await this.apiClient.scaffold(
82
+ {
83
+ body: request
84
+ },
85
+ options
86
+ );
87
+ if (response.status !== 201) {
88
+ const status = `${response.status} ${response.statusText}`;
89
+ const body = await response.text();
90
+ throw new Error(`Backend request failed, ${status} ${body.trim()}`);
91
+ }
92
+ const { id } = await response.json();
93
+ return { taskId: id };
94
+ }
95
+ /**
96
+ * {@inheritdoc ScaffolderApi.getTask}
97
+ */
98
+ async getTask(taskId, options) {
99
+ return await this.requestRequired(
100
+ await this.apiClient.getTask(
101
+ {
102
+ path: { taskId }
103
+ },
104
+ options
105
+ )
106
+ );
107
+ }
108
+ /**
109
+ * {@inheritdoc ScaffolderApi.streamLogs}
110
+ */
111
+ streamLogs(request, options) {
112
+ if (this.useLongPollingLogs) {
113
+ return this.streamLogsPolling(request, options);
114
+ }
115
+ return this.streamLogsEventStream(request);
116
+ }
117
+ /**
118
+ * {@inheritdoc ScaffolderApi.dryRun}
119
+ */
120
+ async dryRun(request, options) {
121
+ return await this.requestRequired(
122
+ await this.apiClient.dryRun(
123
+ {
124
+ body: {
125
+ template: request.template,
126
+ values: request.values,
127
+ secrets: request.secrets,
128
+ directoryContents: request.directoryContents
129
+ }
130
+ },
131
+ options
132
+ )
133
+ );
134
+ }
135
+ streamLogsEventStream({
136
+ isTaskRecoverable,
137
+ taskId,
138
+ after
139
+ }) {
140
+ return new ObservableImpl((subscriber) => {
141
+ const params = new URLSearchParams();
142
+ if (after !== void 0) {
143
+ params.set("after", String(Number(after)));
144
+ }
145
+ this.discoveryApi.getBaseUrl("scaffolder").then(
146
+ (baseUrl) => {
147
+ const url = `${baseUrl}/v2/tasks/${encodeURIComponent(
148
+ taskId
149
+ )}/eventstream`;
150
+ const processEvent = (event) => {
151
+ if (event.data) {
152
+ try {
153
+ subscriber.next(JSON.parse(event.data));
154
+ } catch (ex) {
155
+ subscriber.error(ex);
156
+ }
157
+ }
158
+ };
159
+ const ctrl = new AbortController();
160
+ void fetchEventSource(url, {
161
+ fetch: this.fetchApi.fetch,
162
+ signal: ctrl.signal,
163
+ onmessage(e) {
164
+ if (e.event === "log") {
165
+ processEvent(e);
166
+ return;
167
+ } else if (e.event === "completion" && !isTaskRecoverable) {
168
+ processEvent(e);
169
+ subscriber.complete();
170
+ ctrl.abort();
171
+ return;
172
+ }
173
+ processEvent(e);
174
+ },
175
+ onerror(err) {
176
+ subscriber.error(err);
177
+ }
178
+ });
179
+ },
180
+ (error) => {
181
+ subscriber.error(error);
182
+ }
183
+ );
184
+ });
185
+ }
186
+ streamLogsPolling({
187
+ taskId,
188
+ after: inputAfter
189
+ }, options) {
190
+ let after = inputAfter;
191
+ return new ObservableImpl((subscriber) => {
192
+ (async () => {
193
+ while (!subscriber.closed) {
194
+ const response = await this.apiClient.streamLogsPolling(
195
+ {
196
+ path: { taskId },
197
+ query: { after }
198
+ },
199
+ options
200
+ );
201
+ if (!response.ok) {
202
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
203
+ continue;
204
+ }
205
+ const logs = await response.json();
206
+ for (const event of logs) {
207
+ after = Number(event.id);
208
+ subscriber.next(event);
209
+ if (event.type === "completion") {
210
+ subscriber.complete();
211
+ return;
212
+ }
213
+ }
214
+ }
215
+ })();
216
+ });
217
+ }
218
+ /**
219
+ * {@inheritdoc ScaffolderApi.listActions}
220
+ */
221
+ async listActions(options) {
222
+ return await this.requestRequired(
223
+ await this.apiClient.listActions(null, options)
224
+ );
225
+ }
226
+ /**
227
+ * {@inheritdoc ScaffolderApi.listTemplatingExtensions}
228
+ */
229
+ async listTemplatingExtensions(options) {
230
+ return await this.requestRequired(
231
+ await this.apiClient.listTemplatingExtensions(null, options)
232
+ );
233
+ }
234
+ /**
235
+ * {@inheritdoc ScaffolderApi.cancelTask}
236
+ */
237
+ async cancelTask(taskId, options) {
238
+ return await this.requestRequired(
239
+ await this.apiClient.cancelTask({ path: { taskId } }, options)
240
+ );
241
+ }
242
+ /**
243
+ * {@inheritdoc ScaffolderApi.retry}
244
+ */
245
+ async retry(taskId, options) {
246
+ return await this.requestRequired(
247
+ await this.apiClient.retry({ body: {}, path: { taskId } }, options)
248
+ );
249
+ }
250
+ /**
251
+ * {@inheritdoc ScaffolderApi.retry}
252
+ */
253
+ async autocomplete({
254
+ token,
255
+ resource,
256
+ provider,
257
+ context
258
+ }) {
259
+ return await this.requestRequired(
260
+ await this.apiClient.autocomplete({
261
+ path: { provider, resource },
262
+ body: { token, context }
263
+ })
264
+ );
265
+ }
266
+ //
267
+ // Private methods
268
+ //
269
+ async requestRequired(response) {
270
+ if (!response.ok) {
271
+ throw await ResponseError.fromResponse(response);
272
+ }
273
+ return response.json();
274
+ }
275
+ }
276
+
277
+ export { ScaffolderClient };
278
+ //# sourceMappingURL=ScaffolderClient.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScaffolderClient.esm.js","sources":["../src/ScaffolderClient.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { parseEntityRef } from '@backstage/catalog-model';\nimport { ResponseError } from '@backstage/errors';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport { Observable } from '@backstage/types';\nimport {\n EventSourceMessage,\n fetchEventSource,\n} from '@microsoft/fetch-event-source';\nimport ObservableImpl from 'zen-observable';\n\nimport { type TemplateParameterSchema } from './TemplateEntityV1beta3';\nimport {\n ListActionsResponse,\n ListTemplatingExtensionsResponse,\n LogEvent,\n ScaffolderApi,\n ScaffolderDryRunOptions,\n ScaffolderDryRunResponse,\n ScaffolderGetIntegrationsListOptions,\n ScaffolderGetIntegrationsListResponse,\n ScaffolderRequestOptions,\n ScaffolderScaffoldOptions,\n ScaffolderScaffoldResponse,\n ScaffolderStreamLogsOptions,\n ScaffolderTask,\n} from './api';\nimport { DefaultApiClient, TaskStatus, TypedResponse } from './schema/openapi';\n\n/**\n * An API to interact with the scaffolder backend.\n *\n * @public\n */\nexport class ScaffolderClient implements ScaffolderApi {\n private readonly apiClient: DefaultApiClient;\n private readonly discoveryApi: {\n getBaseUrl(pluginId: string): Promise<string>;\n };\n private readonly scmIntegrationsApi: ScmIntegrationRegistry;\n private readonly fetchApi: { fetch: typeof fetch };\n private readonly identityApi?: {\n getBackstageIdentity(): Promise<{\n type: 'user';\n userEntityRef: string;\n ownershipEntityRefs: string[];\n }>;\n };\n private readonly useLongPollingLogs: boolean;\n\n constructor(options: {\n discoveryApi: { getBaseUrl(pluginId: string): Promise<string> };\n fetchApi: { fetch: typeof fetch };\n identityApi?: {\n getBackstageIdentity(): Promise<{\n type: 'user';\n userEntityRef: string;\n ownershipEntityRefs: string[];\n }>;\n };\n scmIntegrationsApi: ScmIntegrationRegistry;\n useLongPollingLogs?: boolean;\n }) {\n this.apiClient = new DefaultApiClient(options);\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi ?? { fetch };\n this.scmIntegrationsApi = options.scmIntegrationsApi;\n this.useLongPollingLogs = options.useLongPollingLogs ?? false;\n this.identityApi = options.identityApi;\n }\n\n /**\n * {@inheritdoc ScaffolderApi.listTasks}\n */\n async listTasks(\n request: {\n filterByOwnership: 'owned' | 'all';\n limit?: number;\n offset?: number;\n },\n options?: ScaffolderRequestOptions,\n ): Promise<{ tasks: ScaffolderTask[]; totalTasks?: number }> {\n if (!this.identityApi) {\n throw new Error(\n 'IdentityApi is not available in the ScaffolderClient, please pass through the IdentityApi to the ScaffolderClient constructor in order to use the listTasks method',\n );\n }\n\n const { userEntityRef } = await this.identityApi.getBackstageIdentity();\n\n return await this.requestRequired(\n await this.apiClient.listTasks(\n {\n query: {\n createdBy:\n request.filterByOwnership === 'owned'\n ? [userEntityRef]\n : undefined,\n limit: request.limit,\n offset: request.offset,\n },\n },\n options,\n ),\n );\n }\n\n async getIntegrationsList(\n options: ScaffolderGetIntegrationsListOptions,\n ): Promise<ScaffolderGetIntegrationsListResponse> {\n const integrations = [\n ...this.scmIntegrationsApi.azure.list(),\n ...this.scmIntegrationsApi.bitbucket\n .list()\n .filter(\n item =>\n !this.scmIntegrationsApi.bitbucketCloud.byHost(item.config.host) &&\n !this.scmIntegrationsApi.bitbucketServer.byHost(item.config.host),\n ),\n ...this.scmIntegrationsApi.bitbucketCloud.list(),\n ...this.scmIntegrationsApi.bitbucketServer.list(),\n ...this.scmIntegrationsApi.gerrit.list(),\n ...this.scmIntegrationsApi.gitea.list(),\n ...this.scmIntegrationsApi.github.list(),\n ...this.scmIntegrationsApi.gitlab.list(),\n ]\n .map(c => ({ type: c.type, title: c.title, host: c.config.host }))\n .filter(c => options.allowedHosts.includes(c.host));\n\n return {\n integrations,\n };\n }\n\n /**\n * {@inheritdoc ScaffolderApi.getTemplateParameterSchema}\n */\n async getTemplateParameterSchema(\n templateRef: string,\n options?: ScaffolderRequestOptions,\n ): Promise<TemplateParameterSchema> {\n return await this.requestRequired(\n await this.apiClient.getTemplateParameterSchema(\n {\n path: parseEntityRef(templateRef, {\n defaultKind: 'template',\n }),\n },\n options,\n ),\n );\n }\n\n /**\n * {@inheritdoc ScaffolderApi.scaffold}\n */\n async scaffold(\n request: ScaffolderScaffoldOptions,\n options?: ScaffolderRequestOptions,\n ): Promise<ScaffolderScaffoldResponse> {\n const response = await this.apiClient.scaffold(\n {\n body: request,\n },\n options,\n );\n\n if (response.status !== 201) {\n const status = `${response.status} ${response.statusText}`;\n const body = await response.text();\n throw new Error(`Backend request failed, ${status} ${body.trim()}`);\n }\n\n const { id } = await response.json();\n return { taskId: id };\n }\n\n /**\n * {@inheritdoc ScaffolderApi.getTask}\n */\n async getTask(\n taskId: string,\n options?: ScaffolderRequestOptions,\n ): Promise<ScaffolderTask> {\n return await this.requestRequired(\n await this.apiClient.getTask(\n {\n path: { taskId },\n },\n options,\n ),\n );\n }\n\n /**\n * {@inheritdoc ScaffolderApi.streamLogs}\n */\n streamLogs(\n request: ScaffolderStreamLogsOptions,\n options?: ScaffolderRequestOptions,\n ): Observable<LogEvent> {\n if (this.useLongPollingLogs) {\n return this.streamLogsPolling(request, options);\n }\n\n return this.streamLogsEventStream(request);\n }\n\n /**\n * {@inheritdoc ScaffolderApi.dryRun}\n */\n async dryRun(\n request: ScaffolderDryRunOptions,\n options?: ScaffolderRequestOptions,\n ): Promise<ScaffolderDryRunResponse> {\n return await this.requestRequired(\n await this.apiClient.dryRun(\n {\n body: {\n template: request.template,\n values: request.values,\n secrets: request.secrets,\n directoryContents: request.directoryContents,\n },\n },\n options,\n ),\n );\n }\n\n private streamLogsEventStream({\n isTaskRecoverable,\n taskId,\n after,\n }: ScaffolderStreamLogsOptions): Observable<LogEvent> {\n return new ObservableImpl(subscriber => {\n const params = new URLSearchParams();\n if (after !== undefined) {\n params.set('after', String(Number(after)));\n }\n\n this.discoveryApi.getBaseUrl('scaffolder').then(\n baseUrl => {\n const url = `${baseUrl}/v2/tasks/${encodeURIComponent(\n taskId,\n )}/eventstream`;\n\n const processEvent = (event: any) => {\n if (event.data) {\n try {\n subscriber.next(JSON.parse(event.data));\n } catch (ex) {\n subscriber.error(ex);\n }\n }\n };\n\n const ctrl = new AbortController();\n void fetchEventSource(url, {\n fetch: this.fetchApi.fetch,\n signal: ctrl.signal,\n onmessage(e: EventSourceMessage) {\n if (e.event === 'log') {\n processEvent(e);\n return;\n } else if (e.event === 'completion' && !isTaskRecoverable) {\n processEvent(e);\n subscriber.complete();\n ctrl.abort();\n return;\n }\n processEvent(e);\n },\n onerror(err) {\n subscriber.error(err);\n },\n });\n },\n error => {\n subscriber.error(error);\n },\n );\n });\n }\n\n private streamLogsPolling(\n {\n taskId,\n after: inputAfter,\n }: {\n taskId: string;\n after?: number;\n },\n options?: ScaffolderRequestOptions,\n ): Observable<LogEvent> {\n let after = inputAfter;\n\n return new ObservableImpl(subscriber => {\n (async () => {\n while (!subscriber.closed) {\n const response = await this.apiClient.streamLogsPolling(\n {\n path: { taskId },\n query: { after },\n },\n options,\n );\n\n if (!response.ok) {\n // wait for one second to not run into an\n await new Promise(resolve => setTimeout(resolve, 1000));\n continue;\n }\n\n const logs = (await response.json()) as LogEvent[];\n\n for (const event of logs) {\n after = Number(event.id);\n\n subscriber.next(event);\n\n if (event.type === 'completion') {\n subscriber.complete();\n return;\n }\n }\n }\n })();\n });\n }\n\n /**\n * {@inheritdoc ScaffolderApi.listActions}\n */\n async listActions(\n options?: ScaffolderRequestOptions,\n ): Promise<ListActionsResponse> {\n return await this.requestRequired(\n await this.apiClient.listActions(null as any, options),\n );\n }\n\n /**\n * {@inheritdoc ScaffolderApi.listTemplatingExtensions}\n */\n async listTemplatingExtensions(\n options?: ScaffolderRequestOptions,\n ): Promise<ListTemplatingExtensionsResponse> {\n return await this.requestRequired(\n await this.apiClient.listTemplatingExtensions(null as any, options),\n );\n }\n\n /**\n * {@inheritdoc ScaffolderApi.cancelTask}\n */\n async cancelTask(\n taskId: string,\n options?: ScaffolderRequestOptions,\n ): Promise<{ status?: TaskStatus }> {\n return await this.requestRequired(\n await this.apiClient.cancelTask({ path: { taskId } }, options),\n );\n }\n\n /**\n * {@inheritdoc ScaffolderApi.retry}\n */\n async retry?(\n taskId: string,\n options?: ScaffolderRequestOptions,\n ): Promise<{ id: string }> {\n return await this.requestRequired(\n await this.apiClient.retry({ body: {}, path: { taskId } }, options),\n );\n }\n\n /**\n * {@inheritdoc ScaffolderApi.retry}\n */\n async autocomplete({\n token,\n resource,\n provider,\n context,\n }: {\n token: string;\n provider: string;\n resource: string;\n context: Record<string, string>;\n }): Promise<{ results: { title?: string; id: string }[] }> {\n return await this.requestRequired(\n await this.apiClient.autocomplete({\n path: { provider, resource },\n body: { token, context },\n }),\n );\n }\n\n //\n // Private methods\n //\n\n private async requestRequired<T>(response: TypedResponse<T>): Promise<T> {\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return response.json();\n }\n}\n"],"names":[],"mappings":"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"}