add a createDeferred and DeferredPromise to the types
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/types': minor
|
||||
---
|
||||
|
||||
Introduce `createDeferred` and `DeferredPromise`.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
'@backstage/config-loader': patch
|
||||
---
|
||||
|
||||
Internal refactor to use the deferred from the types package
|
||||
+5
-12
@@ -26,14 +26,7 @@ import {
|
||||
PluginTaskSchedulerImpl,
|
||||
parseDuration,
|
||||
} from './PluginTaskSchedulerImpl';
|
||||
|
||||
function defer() {
|
||||
let resolve = () => {};
|
||||
const promise = new Promise<void>(_resolve => {
|
||||
resolve = _resolve;
|
||||
});
|
||||
return { promise, resolve };
|
||||
}
|
||||
import { createDeferred } from '@backstage/types';
|
||||
|
||||
jest.setTimeout(60_000);
|
||||
|
||||
@@ -188,14 +181,14 @@ describe('PluginTaskManagerImpl', () => {
|
||||
async databaseId => {
|
||||
const { manager } = await init(databaseId);
|
||||
|
||||
const { promise, resolve } = defer();
|
||||
const promise = createDeferred();
|
||||
|
||||
await manager.scheduleTask({
|
||||
id: 'task1',
|
||||
timeout: Duration.fromMillis(5000),
|
||||
frequency: Duration.fromObject({ years: 1 }),
|
||||
fn: async () => {
|
||||
resolve();
|
||||
promise.resolve();
|
||||
await new Promise(r => setTimeout(r, 20000));
|
||||
},
|
||||
scope: 'global',
|
||||
@@ -313,14 +306,14 @@ describe('PluginTaskManagerImpl', () => {
|
||||
it('cant trigger a running task', async () => {
|
||||
const { manager } = await init('SQLITE_3');
|
||||
|
||||
const { promise, resolve } = defer();
|
||||
const promise = createDeferred();
|
||||
|
||||
await manager.scheduleTask({
|
||||
id: 'task1',
|
||||
timeout: Duration.fromMillis(5000),
|
||||
frequency: Duration.fromObject({ years: 1 }),
|
||||
fn: async () => {
|
||||
resolve();
|
||||
promise.resolve();
|
||||
await new Promise(r => setTimeout(r, 20000));
|
||||
},
|
||||
scope: 'local',
|
||||
|
||||
@@ -20,6 +20,7 @@ import fs from 'fs-extra';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { createMockDirectory } from '@backstage/backend-test-utils';
|
||||
import { createDeferred } from '@backstage/types';
|
||||
|
||||
describe('loadConfig', () => {
|
||||
const mockDir = createMockDirectory({
|
||||
@@ -298,8 +299,8 @@ describe('loadConfig', () => {
|
||||
});
|
||||
|
||||
it('watches config files', async () => {
|
||||
const onChange = defer<AppConfig[]>();
|
||||
const stopSignal = defer<void>();
|
||||
const onChange = createDeferred<AppConfig[]>();
|
||||
const stopSignal = createDeferred();
|
||||
|
||||
await expect(
|
||||
loadConfig({
|
||||
@@ -307,7 +308,7 @@ describe('loadConfig', () => {
|
||||
configTargets: [],
|
||||
watch: {
|
||||
onChange: onChange.resolve,
|
||||
stopSignal: stopSignal.promise,
|
||||
stopSignal,
|
||||
},
|
||||
}),
|
||||
).resolves.toEqual({
|
||||
@@ -331,7 +332,7 @@ describe('loadConfig', () => {
|
||||
title: 'New Title',
|
||||
},
|
||||
});
|
||||
await expect(onChange.promise).resolves.toEqual([
|
||||
await expect(onChange).resolves.toEqual([
|
||||
{
|
||||
context: 'app-config.yaml',
|
||||
data: {
|
||||
@@ -347,8 +348,8 @@ describe('loadConfig', () => {
|
||||
});
|
||||
|
||||
it('watches included files', async () => {
|
||||
const onChange = defer<AppConfig[]>();
|
||||
const stopSignal = defer<void>();
|
||||
const onChange = createDeferred<AppConfig[]>();
|
||||
const stopSignal = createDeferred();
|
||||
|
||||
await expect(
|
||||
loadConfig({
|
||||
@@ -358,7 +359,7 @@ describe('loadConfig', () => {
|
||||
],
|
||||
watch: {
|
||||
onChange: onChange.resolve,
|
||||
stopSignal: stopSignal.promise,
|
||||
stopSignal,
|
||||
},
|
||||
}),
|
||||
).resolves.toEqual({
|
||||
@@ -387,7 +388,7 @@ describe('loadConfig', () => {
|
||||
// via included.yaml
|
||||
await fs.writeFile(mockDir.resolve('secrets/session-key.txt'), 'abc234');
|
||||
|
||||
await expect(onChange.promise).resolves.toEqual([
|
||||
await expect(onChange).resolves.toEqual([
|
||||
{
|
||||
context: 'app-config.development.yaml',
|
||||
data: {
|
||||
@@ -413,8 +414,8 @@ describe('loadConfig', () => {
|
||||
it('watches remote config urls', async () => {
|
||||
server.use(initialLoaderHandler);
|
||||
|
||||
const onChange = defer<AppConfig[]>();
|
||||
const stopSignal = defer<void>();
|
||||
const onChange = createDeferred<AppConfig[]>();
|
||||
const stopSignal = createDeferred();
|
||||
|
||||
const configUrl = 'https://some.domain.io/app-config.yaml';
|
||||
await expect(
|
||||
@@ -423,7 +424,7 @@ describe('loadConfig', () => {
|
||||
configTargets: [{ url: configUrl }],
|
||||
watch: {
|
||||
onChange: onChange.resolve,
|
||||
stopSignal: stopSignal.promise,
|
||||
stopSignal,
|
||||
},
|
||||
remote: {
|
||||
reloadIntervalSeconds: 1,
|
||||
@@ -446,7 +447,7 @@ describe('loadConfig', () => {
|
||||
|
||||
server.use(reloadHandler);
|
||||
|
||||
await expect(onChange.promise).resolves.toEqual([
|
||||
await expect(onChange).resolves.toEqual([
|
||||
{
|
||||
context: configUrl,
|
||||
data: {
|
||||
@@ -463,7 +464,7 @@ describe('loadConfig', () => {
|
||||
});
|
||||
|
||||
it('stops watching config files', async () => {
|
||||
const stopSignal = defer<void>();
|
||||
const stopSignal = createDeferred();
|
||||
|
||||
await loadConfig({
|
||||
configRoot: mockDir.path,
|
||||
@@ -472,7 +473,7 @@ describe('loadConfig', () => {
|
||||
onChange: () => {
|
||||
expect('not').toBe('called');
|
||||
},
|
||||
stopSignal: stopSignal.promise,
|
||||
stopSignal,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -496,12 +497,4 @@ describe('loadConfig', () => {
|
||||
appConfigs: [],
|
||||
});
|
||||
});
|
||||
|
||||
function defer<T>() {
|
||||
let resolve: (value: T) => void;
|
||||
const promise = new Promise<T>(_resolve => {
|
||||
resolve = _resolve;
|
||||
});
|
||||
return { promise, resolve: resolve! };
|
||||
}
|
||||
});
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { DeferredPromise, JsonObject, createDeferred } from '@backstage/types';
|
||||
import {
|
||||
AsyncConfigSourceGenerator,
|
||||
ConfigSource,
|
||||
ReadConfigDataOptions,
|
||||
} from './types';
|
||||
import { simpleDefer, SimpleDeferred, waitOrAbort } from './utils';
|
||||
import { waitOrAbort } from './utils';
|
||||
|
||||
/**
|
||||
* Options for {@link MutableConfigSource.create}.
|
||||
@@ -52,20 +52,20 @@ export class MutableConfigSource implements ConfigSource {
|
||||
}
|
||||
|
||||
#currentData?: JsonObject;
|
||||
#deferred: SimpleDeferred<void>;
|
||||
#deferred: DeferredPromise<void>;
|
||||
readonly #context: string;
|
||||
readonly #abortController = new AbortController();
|
||||
|
||||
private constructor(context: string, initialData?: JsonObject) {
|
||||
this.#currentData = initialData;
|
||||
this.#context = context;
|
||||
this.#deferred = simpleDefer();
|
||||
this.#deferred = createDeferred();
|
||||
}
|
||||
|
||||
async *readConfigData(
|
||||
options?: ReadConfigDataOptions | undefined,
|
||||
): AsyncConfigSourceGenerator {
|
||||
let deferredPromise = this.#deferred.promise;
|
||||
let deferredPromise = this.#deferred;
|
||||
|
||||
if (this.#currentData !== undefined) {
|
||||
yield { configs: [{ data: this.#currentData, context: this.#context }] };
|
||||
@@ -79,7 +79,7 @@ export class MutableConfigSource implements ConfigSource {
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
deferredPromise = this.#deferred.promise;
|
||||
deferredPromise = this.#deferred;
|
||||
|
||||
if (this.#currentData !== undefined) {
|
||||
yield {
|
||||
@@ -98,7 +98,7 @@ export class MutableConfigSource implements ConfigSource {
|
||||
if (!this.#abortController.signal.aborted) {
|
||||
this.#currentData = data;
|
||||
const oldDeferred = this.#deferred;
|
||||
this.#deferred = simpleDefer();
|
||||
this.#deferred = createDeferred();
|
||||
oldDeferred.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,13 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { JsonObject, Observable } from '@backstage/types';
|
||||
import { JsonObject, Observable, createDeferred } from '@backstage/types';
|
||||
import {
|
||||
AsyncConfigSourceGenerator,
|
||||
ConfigSource,
|
||||
ReadConfigDataOptions,
|
||||
} from './types';
|
||||
import { simpleDefer } from './utils';
|
||||
|
||||
/**
|
||||
* Options for {@link StaticConfigSource.create}.
|
||||
@@ -47,13 +46,13 @@ class StaticObservableConfigSource implements ConfigSource {
|
||||
options?: ReadConfigDataOptions | undefined,
|
||||
): AsyncConfigSourceGenerator {
|
||||
const queue = new Array<JsonObject>();
|
||||
let deferred = simpleDefer<void>();
|
||||
let deferred = createDeferred();
|
||||
|
||||
const sub = this.data.subscribe({
|
||||
next(value) {
|
||||
queue.push(value);
|
||||
deferred.resolve();
|
||||
deferred = simpleDefer();
|
||||
deferred = createDeferred();
|
||||
},
|
||||
complete() {
|
||||
deferred.resolve();
|
||||
@@ -73,7 +72,7 @@ class StaticObservableConfigSource implements ConfigSource {
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
await deferred.promise;
|
||||
await deferred;
|
||||
if (queue.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -17,21 +17,6 @@
|
||||
import { Parser } from './types';
|
||||
import yaml from 'yaml';
|
||||
|
||||
/** @internal */
|
||||
export interface SimpleDeferred<T> {
|
||||
promise: Promise<T>;
|
||||
resolve(value: T): void;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function simpleDefer<T>(): SimpleDeferred<T> {
|
||||
let resolve: (value: T) => void;
|
||||
const promise = new Promise<T>(_resolve => {
|
||||
resolve = _resolve;
|
||||
});
|
||||
return { promise, resolve: resolve! };
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export async function waitOrAbort<T>(
|
||||
promise: PromiseLike<T>,
|
||||
|
||||
@@ -3,6 +3,21 @@
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
// @public
|
||||
export function createDeferred<
|
||||
TResolved = void,
|
||||
TRejected = Error,
|
||||
>(): DeferredPromise<TResolved, TRejected>;
|
||||
|
||||
// @public
|
||||
export type DeferredPromise<
|
||||
TResolved = void,
|
||||
TRejected = Error,
|
||||
> = Promise<TResolved> & {
|
||||
resolve(value: TResolved | PromiseLike<TResolved>): void;
|
||||
reject(reason?: TRejected): void;
|
||||
};
|
||||
|
||||
// @public
|
||||
export function durationToMilliseconds(duration: HumanDuration): number;
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createDeferred } from './deferred';
|
||||
|
||||
describe('createDeferred', () => {
|
||||
it('can both resolve and reject', async () => {
|
||||
const d1 = createDeferred<number>();
|
||||
const d2 = createDeferred<string>();
|
||||
const d3 = createDeferred<object>();
|
||||
const d4 = createDeferred(); // test the implicit void
|
||||
|
||||
const d1resolved = jest.fn<void, [number]>();
|
||||
const d1rejected = jest.fn();
|
||||
d1.then(d1resolved, d1rejected);
|
||||
|
||||
const d2resolved = jest.fn<void, [string]>();
|
||||
const d2rejected = jest.fn();
|
||||
d2.then(d2resolved, d2rejected);
|
||||
|
||||
const d3resolved = jest.fn<void, [number]>();
|
||||
const d3rejected = jest.fn();
|
||||
// @ts-expect-error wrong argument type for resolved
|
||||
d3.then(d3resolved, d3rejected);
|
||||
|
||||
const d4resolved = jest.fn<void, [number]>();
|
||||
const d4rejected = jest.fn();
|
||||
// @ts-expect-error resolver should not take arguments for void deferred
|
||||
d4.then(d4resolved, d4rejected);
|
||||
|
||||
d1.resolve(1);
|
||||
d1.resolve(2); // should have no effect
|
||||
|
||||
// @ts-expect-error wrong argument type for resolve
|
||||
d2.resolve(1);
|
||||
d2.reject(new Error('boom')); // should have no effect
|
||||
|
||||
d3.reject(new Error('boom'));
|
||||
|
||||
// @ts-expect-error void deferred does not take arguments
|
||||
d4.resolve(1);
|
||||
|
||||
await 'a tick';
|
||||
|
||||
expect(d1resolved).toHaveBeenCalledTimes(1);
|
||||
expect(d1resolved).toHaveBeenCalledWith(1);
|
||||
expect(d1rejected).not.toHaveBeenCalled();
|
||||
|
||||
expect(d1resolved).toHaveBeenCalledTimes(1);
|
||||
expect(d2resolved).toHaveBeenCalledWith(1);
|
||||
expect(d1rejected).not.toHaveBeenCalled();
|
||||
|
||||
expect(d3resolved).not.toHaveBeenCalled();
|
||||
expect(d3rejected).toHaveBeenCalledTimes(1);
|
||||
expect(d3rejected).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ message: 'boom' }),
|
||||
);
|
||||
|
||||
expect(`${d1}`).toBe('[object DeferredPromise]');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A deferred promise that can be resolved or rejected later.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type DeferredPromise<
|
||||
TResolved = void,
|
||||
TRejected = Error,
|
||||
> = Promise<TResolved> & {
|
||||
resolve(value: TResolved | PromiseLike<TResolved>): void;
|
||||
reject(reason?: TRejected): void;
|
||||
};
|
||||
|
||||
class Deferred<TResolved, TRejected>
|
||||
implements DeferredPromise<TResolved, TRejected>
|
||||
{
|
||||
#resolve?: (value: TResolved | PromiseLike<TResolved>) => void;
|
||||
#reject?: (reason?: TRejected) => void;
|
||||
|
||||
public get resolve() {
|
||||
return this.#resolve!;
|
||||
}
|
||||
public get reject() {
|
||||
return this.#reject!;
|
||||
}
|
||||
|
||||
public then: Promise<TResolved>['then'];
|
||||
public catch: Promise<TResolved>['catch'];
|
||||
public finally: Promise<TResolved>['finally'];
|
||||
|
||||
public constructor() {
|
||||
const promise = new Promise<TResolved>((resolve, reject) => {
|
||||
this.#resolve = resolve;
|
||||
this.#reject = reject;
|
||||
});
|
||||
|
||||
this.then = promise.then.bind(promise);
|
||||
this.catch = promise.catch.bind(promise);
|
||||
this.finally = promise.finally.bind(promise);
|
||||
}
|
||||
|
||||
[Symbol.toStringTag]: 'DeferredPromise' = 'DeferredPromise';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a deferred promise that can be resolved or rejected later.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function createDeferred<
|
||||
TResolved = void,
|
||||
TRejected = Error,
|
||||
>(): DeferredPromise<TResolved, TRejected> {
|
||||
return new Deferred();
|
||||
}
|
||||
@@ -20,6 +20,7 @@
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export { createDeferred, type DeferredPromise } from './deferred';
|
||||
export type { JsonArray, JsonObject, JsonPrimitive, JsonValue } from './json';
|
||||
export type { Observable, Observer, Subscription } from './observable';
|
||||
export { type HumanDuration, durationToMilliseconds } from './time';
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
EntityProvider,
|
||||
EntityProviderConnection,
|
||||
} from '@backstage/plugin-catalog-node';
|
||||
import { createDeferred } from '@backstage/types';
|
||||
import express from 'express';
|
||||
import { Knex } from 'knex';
|
||||
import { Duration } from 'luxon';
|
||||
@@ -35,7 +36,6 @@ import {
|
||||
IncrementalEntityProvider,
|
||||
IncrementalEntityProviderOptions,
|
||||
} from '../types';
|
||||
import { Deferred } from '../util';
|
||||
|
||||
/**
|
||||
* Helps in the creation of the catalog entity providers that wrap the
|
||||
@@ -44,7 +44,7 @@ import { Deferred } from '../util';
|
||||
export class WrapperProviders {
|
||||
private migrate: Promise<void> | undefined;
|
||||
private numberOfProvidersToConnect = 0;
|
||||
private readonly readySignal = new Deferred<void>();
|
||||
private readonly readySignal = createDeferred();
|
||||
|
||||
constructor(
|
||||
private readonly options: {
|
||||
|
||||
+3
-5
@@ -20,13 +20,13 @@ import {
|
||||
PluginEnvironment,
|
||||
} from '../types';
|
||||
import { CatalogBuilder as CoreCatalogBuilder } from '@backstage/plugin-catalog-backend';
|
||||
import { createDeferred } from '@backstage/types';
|
||||
import { Duration } from 'luxon';
|
||||
import { Knex } from 'knex';
|
||||
import { IncrementalIngestionEngine } from '../engine/IncrementalIngestionEngine';
|
||||
import { applyDatabaseMigrations } from '../database/migrations';
|
||||
import { IncrementalIngestionDatabaseManager } from '../database/IncrementalIngestionDatabaseManager';
|
||||
import { IncrementalProviderRouter } from '../router/routes';
|
||||
import { Deferred } from '../util';
|
||||
import { EventParams, EventSubscriber } from '@backstage/plugin-events-node';
|
||||
|
||||
/** @public */
|
||||
@@ -43,16 +43,14 @@ export class IncrementalCatalogBuilder {
|
||||
return new IncrementalCatalogBuilder(env, builder, client, manager);
|
||||
}
|
||||
|
||||
private ready: Deferred<void>;
|
||||
private ready = createDeferred();
|
||||
|
||||
private constructor(
|
||||
private env: PluginEnvironment,
|
||||
private builder: CoreCatalogBuilder,
|
||||
private client: Knex,
|
||||
private manager: IncrementalIngestionDatabaseManager,
|
||||
) {
|
||||
this.ready = new Deferred<void>();
|
||||
}
|
||||
) {}
|
||||
|
||||
async build() {
|
||||
await applyDatabaseMigrations(this.client);
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export class Deferred<T> implements Promise<T> {
|
||||
#resolve?: (value: T) => void;
|
||||
#reject?: (error: Error) => void;
|
||||
|
||||
public get resolve() {
|
||||
return this.#resolve!;
|
||||
}
|
||||
public get reject() {
|
||||
return this.#reject!;
|
||||
}
|
||||
|
||||
public then: Promise<T>['then'];
|
||||
public catch: Promise<T>['catch'];
|
||||
public finally: Promise<T>['finally'];
|
||||
|
||||
public constructor() {
|
||||
const promise = new Promise<T>((resolve, reject) => {
|
||||
this.#resolve = resolve;
|
||||
this.#reject = reject;
|
||||
});
|
||||
|
||||
this.then = promise.then.bind(promise);
|
||||
this.catch = promise.catch.bind(promise);
|
||||
this.finally = promise.finally.bind(promise);
|
||||
}
|
||||
|
||||
[Symbol.toStringTag]: 'Deferred' = 'Deferred';
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
startTestBackend,
|
||||
} from '@backstage/backend-test-utils';
|
||||
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
|
||||
import { createDeferred } from '@backstage/types';
|
||||
import { Knex } from 'knex';
|
||||
import { applyDatabaseMigrations } from '../../database/migrations';
|
||||
import {
|
||||
@@ -33,16 +34,6 @@ import { describePerformanceTest, performanceTraceEnabled } from './lib/env';
|
||||
|
||||
jest.setTimeout(600_000);
|
||||
|
||||
function defer<T>() {
|
||||
let resolve: (value: T | PromiseLike<T>) => void;
|
||||
let reject: (error?: unknown) => void;
|
||||
const promise = new Promise<T>((_resolve, _reject) => {
|
||||
resolve = _resolve;
|
||||
reject = _reject;
|
||||
});
|
||||
return { promise, resolve: resolve!, reject: reject! };
|
||||
}
|
||||
|
||||
const traceLog: typeof console.log = performanceTraceEnabled
|
||||
? console.log
|
||||
: () => {};
|
||||
@@ -50,7 +41,7 @@ const traceLog: typeof console.log = performanceTraceEnabled
|
||||
class Tracker {
|
||||
private insertBaseEntitiesStart: number | undefined;
|
||||
private insertBaseEntitiesEnd: number | undefined;
|
||||
private readonly deferred = defer<void>();
|
||||
private readonly deferred = createDeferred();
|
||||
|
||||
constructor(
|
||||
private readonly knex: Knex,
|
||||
@@ -93,7 +84,7 @@ class Tracker {
|
||||
}
|
||||
|
||||
async completion(): Promise<void> {
|
||||
return this.deferred.promise;
|
||||
return this.deferred;
|
||||
}
|
||||
|
||||
private completionPolling() {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import { TestApiProvider, renderInTestApp } from '@backstage/test-utils';
|
||||
import { createDeferred } from '@backstage/types';
|
||||
import { screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import ObservableImpl from 'zen-observable';
|
||||
@@ -25,14 +26,6 @@ import {
|
||||
} from '../../apis';
|
||||
import { EntityDisplayName } from './EntityDisplayName';
|
||||
|
||||
function defer<T>() {
|
||||
let resolve = (_value: T) => {};
|
||||
const promise = new Promise<T>(_resolve => {
|
||||
resolve = _resolve;
|
||||
});
|
||||
return { promise, resolve };
|
||||
}
|
||||
|
||||
describe('<EntityDisplayName />', () => {
|
||||
const entityPresentationApi = {
|
||||
forEntity: jest.fn(),
|
||||
@@ -63,7 +56,7 @@ describe('<EntityDisplayName />', () => {
|
||||
});
|
||||
|
||||
it('works with the async the happy path', async () => {
|
||||
const { promise, resolve } = defer<EntityRefPresentationSnapshot>();
|
||||
const promise = createDeferred<EntityRefPresentationSnapshot>();
|
||||
|
||||
entityPresentationApi.forEntity.mockReturnValue({
|
||||
snapshot: {
|
||||
@@ -89,7 +82,7 @@ describe('<EntityDisplayName />', () => {
|
||||
|
||||
expect(screen.getByText('foo')).toBeInTheDocument();
|
||||
|
||||
resolve({
|
||||
promise.resolve({
|
||||
entityRef: 'component:default/foo',
|
||||
primaryTitle: 'bar',
|
||||
});
|
||||
|
||||
+5
-12
@@ -22,14 +22,7 @@ import React from 'react';
|
||||
import { useUnregisterEntityDialogState } from './useUnregisterEntityDialogState';
|
||||
import { TestApiProvider } from '@backstage/test-utils';
|
||||
import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils';
|
||||
|
||||
function defer<T>(): { promise: Promise<T>; resolve: (value: T) => void } {
|
||||
let resolve: (value: T) => void = () => {};
|
||||
const promise = new Promise<T>(_resolve => {
|
||||
resolve = _resolve;
|
||||
});
|
||||
return { promise, resolve };
|
||||
}
|
||||
import { createDeferred } from '@backstage/types';
|
||||
|
||||
describe('useUnregisterEntityDialogState', () => {
|
||||
const catalogApi = catalogApiMock.mock();
|
||||
@@ -47,15 +40,15 @@ describe('useUnregisterEntityDialogState', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
|
||||
const deferredLocation = defer<Location | undefined>();
|
||||
const deferredColocatedEntities = defer<Entity[]>();
|
||||
const deferredLocation = createDeferred<Location | undefined>();
|
||||
const deferredColocatedEntities = createDeferred<Entity[]>();
|
||||
|
||||
resolveLocation = deferredLocation.resolve;
|
||||
resolveColocatedEntities = deferredColocatedEntities.resolve;
|
||||
|
||||
catalogApi.getLocationByRef.mockReturnValue(deferredLocation.promise);
|
||||
catalogApi.getLocationByRef.mockReturnValue(deferredLocation);
|
||||
catalogApi.getEntities.mockReturnValue(
|
||||
deferredColocatedEntities.promise.then(items => ({ items })),
|
||||
deferredColocatedEntities.then(items => ({ items })),
|
||||
);
|
||||
|
||||
entity = {
|
||||
|
||||
@@ -16,7 +16,12 @@
|
||||
|
||||
import { Config } from '@backstage/config';
|
||||
import { TaskSpec } from '@backstage/plugin-scaffolder-common';
|
||||
import { JsonObject, JsonValue, Observable } from '@backstage/types';
|
||||
import {
|
||||
JsonObject,
|
||||
JsonValue,
|
||||
Observable,
|
||||
createDeferred,
|
||||
} from '@backstage/types';
|
||||
import { Logger } from 'winston';
|
||||
import ObservableImpl from 'zen-observable';
|
||||
import {
|
||||
@@ -260,14 +265,6 @@ export interface CurrentClaimedTask {
|
||||
workspace?: Promise<Buffer>;
|
||||
}
|
||||
|
||||
function defer() {
|
||||
let resolve = () => {};
|
||||
const promise = new Promise<void>(_resolve => {
|
||||
resolve = _resolve;
|
||||
});
|
||||
return { promise, resolve };
|
||||
}
|
||||
|
||||
export class StorageTaskBroker implements TaskBroker {
|
||||
constructor(
|
||||
private readonly storage: TaskStore,
|
||||
@@ -301,7 +298,7 @@ export class StorageTaskBroker implements TaskBroker {
|
||||
return await this.storage.list(options ?? {});
|
||||
}
|
||||
|
||||
private deferredDispatch = defer();
|
||||
private deferredDispatch = createDeferred();
|
||||
|
||||
private async registerCancellable(
|
||||
taskId: string,
|
||||
@@ -469,12 +466,12 @@ export class StorageTaskBroker implements TaskBroker {
|
||||
}
|
||||
|
||||
private waitForDispatch() {
|
||||
return this.deferredDispatch.promise;
|
||||
return this.deferredDispatch;
|
||||
}
|
||||
|
||||
private signalDispatch() {
|
||||
this.deferredDispatch.resolve();
|
||||
this.deferredDispatch = defer();
|
||||
this.deferredDispatch = createDeferred();
|
||||
}
|
||||
|
||||
async cancel(taskId: string) {
|
||||
|
||||
Reference in New Issue
Block a user