Merge branch 'backstage:master' into plugin-azure-functions

This commit is contained in:
Wesley
2022-10-09 19:09:03 +02:00
committed by GitHub
496 changed files with 7737 additions and 771 deletions
+11
View File
@@ -1,5 +1,16 @@
# @backstage/app-defaults
## 1.0.7-next.1
### Patch Changes
- Updated dependencies
- @backstage/core-app-api@1.1.1-next.1
- @backstage/core-components@0.11.2-next.1
- @backstage/core-plugin-api@1.0.7-next.1
- @backstage/theme@0.2.16
- @backstage/plugin-permission-react@0.4.6-next.1
## 1.0.7-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/app-defaults",
"description": "Provides the default wiring of a Backstage App",
"version": "1.0.7-next.0",
"version": "1.0.7-next.1",
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",
+62
View File
@@ -1,5 +1,67 @@
# example-app
## 0.2.76-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-user-settings@0.5.0-next.1
- @backstage/plugin-scaffolder@1.7.0-next.1
- @backstage/plugin-catalog-react@1.2.0-next.1
- @backstage/core-app-api@1.1.1-next.1
- @backstage/cli@0.20.0-next.1
- @backstage/plugin-tech-insights@0.3.1-next.1
- @backstage/plugin-gcalendar@0.3.6-next.1
- @backstage/plugin-api-docs@0.8.10-next.1
- @backstage/plugin-search-react@1.2.0-next.1
- @backstage/plugin-search-common@1.1.0-next.1
- @backstage/plugin-airbrake@0.3.10-next.1
- @backstage/plugin-azure-devops@0.2.1-next.1
- @backstage/plugin-badges@0.2.34-next.1
- @internal/plugin-catalog-customized@0.0.3-next.1
- @backstage/plugin-catalog-graph@0.2.22-next.1
- @backstage/plugin-catalog-import@0.8.13-next.1
- @backstage/plugin-circleci@0.3.10-next.1
- @backstage/plugin-cloudbuild@0.3.10-next.1
- @backstage/plugin-code-coverage@0.2.3-next.1
- @backstage/plugin-dynatrace@1.0.0-next.1
- @backstage/plugin-explore@0.3.41-next.1
- @backstage/plugin-github-actions@0.5.10-next.1
- @backstage/plugin-gocd@0.1.16-next.1
- @backstage/plugin-home@0.4.26-next.1
- @backstage/plugin-jenkins@0.7.9-next.1
- @backstage/plugin-kafka@0.3.10-next.1
- @backstage/plugin-kubernetes@0.7.3-next.1
- @backstage/plugin-lighthouse@0.3.10-next.1
- @backstage/plugin-newrelic-dashboard@0.2.3-next.1
- @backstage/plugin-org@0.5.10-next.1
- @backstage/plugin-pagerduty@0.5.3-next.1
- @backstage/plugin-playlist@0.1.1-next.1
- @backstage/plugin-rollbar@0.4.10-next.1
- @backstage/plugin-search@1.0.3-next.1
- @backstage/plugin-sentry@0.4.3-next.1
- @backstage/plugin-techdocs@1.3.3-next.1
- @backstage/plugin-todo@0.2.12-next.1
- @backstage/app-defaults@1.0.7-next.1
- @backstage/core-components@0.11.2-next.1
- @backstage/core-plugin-api@1.0.7-next.1
- @backstage/plugin-apache-airflow@0.2.3-next.1
- @backstage/plugin-cost-insights@0.11.32-next.1
- @backstage/plugin-gcp-projects@0.3.29-next.1
- @backstage/plugin-graphiql@0.2.42-next.1
- @backstage/plugin-newrelic@0.3.28-next.1
- @backstage/plugin-shortcuts@0.3.2-next.1
- @backstage/plugin-stack-overflow@0.1.6-next.1
- @backstage/plugin-tech-radar@0.5.17-next.1
- @backstage/plugin-techdocs-module-addons-contrib@1.0.5-next.1
- @backstage/catalog-model@1.1.2-next.1
- @backstage/config@1.0.3-next.1
- @backstage/integration-react@1.1.5-next.1
- @backstage/theme@0.2.16
- @backstage/plugin-catalog-common@1.0.7-next.1
- @backstage/plugin-permission-react@0.4.6-next.1
- @backstage/plugin-techdocs-react@1.0.5-next.1
## 0.2.76-next.0
### Patch Changes
+2 -1
View File
@@ -1,6 +1,6 @@
{
"name": "example-app",
"version": "0.2.76-next.0",
"version": "0.2.76-next.1",
"private": true,
"backstage": {
"role": "frontend"
@@ -68,6 +68,7 @@
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.57",
"@octokit/rest": "^19.0.3",
"@oriflame/backstage-plugin-score-card": "^0.5.1",
"@roadiehq/backstage-plugin-buildkite": "^2.0.8",
"@roadiehq/backstage-plugin-github-insights": "^2.0.5",
"@roadiehq/backstage-plugin-github-pull-requests": "^2.2.7",
+2
View File
@@ -106,6 +106,7 @@ import { RequirePermission } from '@backstage/plugin-permission-react';
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common';
import { PlaylistIndexPage } from '@backstage/plugin-playlist';
import { TwoColumnLayout } from './components/scaffolder/customScaffolderLayouts';
import { ScoreBoardPage } from '@oriflame/backstage-plugin-score-card';
const app = createApp({
apis,
@@ -273,6 +274,7 @@ const routes = (
<Route path="/azure-pull-requests" element={<AzurePullRequestsPage />} />
<Route path="/apache-airflow" element={<ApacheAirflowPage />} />
<Route path="/playlist" element={<PlaylistIndexPage />} />
<Route path="/score-board" element={<ScoreBoardPage />} />
</FlatRoutes>
);
@@ -51,6 +51,7 @@ import {
import { MyGroupsSidebarItem } from '@backstage/plugin-org';
import GroupIcon from '@material-ui/icons/People';
import { SearchModal } from '../search/SearchModal';
import Score from '@material-ui/icons/Score';
const useSidebarLogoStyles = makeStyles({
root: {
@@ -120,6 +121,7 @@ export const Root = ({ children }: PropsWithChildren<{}>) => (
text="Cost Insights"
/>
<SidebarItem icon={GraphiQLIcon} to="graphiql" text="GraphiQL" />
<SidebarItem icon={Score} to="score-board" text="Score board" />
</SidebarScrollWrapper>
<SidebarDivider />
<Shortcuts />
@@ -144,6 +144,7 @@ import {
EntityNewRelicDashboardCard,
} from '@backstage/plugin-newrelic-dashboard';
import { EntityGoCdContent, isGoCdAvailable } from '@backstage/plugin-gocd';
import { EntityScoreCardContent } from '@oriflame/backstage-plugin-score-card';
import React, { ReactNode, useMemo, useState } from 'react';
@@ -704,6 +705,13 @@ const systemPage = (
</Grid>
</Grid>
</EntityLayout.Route>
<EntityLayout.Route path="/score" title="Score">
<Grid container spacing={3} alignItems="stretch">
<Grid item xs={12}>
<EntityScoreCardContent />
</Grid>
</Grid>
</EntityLayout.Route>
<EntityLayout.Route path="/diagram" title="Diagram">
<EntityCatalogGraphCard
variant="gridItem"
+11
View File
@@ -1,5 +1,16 @@
# @backstage/backend-app-api
## 0.2.2-next.1
### Patch Changes
- Updated dependencies
- @backstage/backend-common@0.15.2-next.1
- @backstage/backend-plugin-api@0.1.3-next.1
- @backstage/backend-tasks@0.3.6-next.1
- @backstage/errors@1.1.2-next.1
- @backstage/plugin-permission-node@0.6.6-next.1
## 0.2.2-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-app-api",
"description": "Core API used by Backstage backend apps",
"version": "0.2.2-next.0",
"version": "0.2.2-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
+13
View File
@@ -1,5 +1,18 @@
# @backstage/backend-common
## 0.15.2-next.1
### Patch Changes
- c31f7cdfbc: Fixed an issue where `getClient()` for a `pluginId` would return different clients and not share them
- Updated dependencies
- @backstage/cli-common@0.1.10
- @backstage/config@1.0.3-next.1
- @backstage/config-loader@1.1.5-next.1
- @backstage/errors@1.1.2-next.1
- @backstage/integration@1.3.2-next.1
- @backstage/types@1.0.0
## 0.15.2-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-common",
"description": "Common functionality library for Backstage backends",
"version": "0.15.2-next.0",
"version": "0.15.2-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
@@ -113,7 +113,11 @@ describe('DatabaseManager', () => {
},
},
};
const manager = DatabaseManager.fromConfig(new ConfigReader(config));
let manager: DatabaseManager;
beforeEach(() => {
manager = DatabaseManager.fromConfig(new ConfigReader(config));
});
it('connects to a plugin database using default config', async () => {
const pluginId = 'pluginwithoutconfig';
@@ -340,6 +344,16 @@ describe('DatabaseManager', () => {
);
});
it('returns the same client for the same pluginId', async () => {
const [client1, client2] = await Promise.all([
manager.forPlugin('plugin1').getClient(),
manager.forPlugin('plugin1').getClient(),
]);
expect(mocked(createDatabaseClient)).toHaveBeenCalledTimes(1);
expect(client1).toBe(client2);
});
it('uses plugin connection as base if default client is different from plugin client', async () => {
const pluginId = 'differentclient';
await manager.forPlugin(pluginId).getClient();
@@ -84,6 +84,7 @@ export class DatabaseManager {
private readonly config: Config,
private readonly prefix: string = 'backstage_plugin_',
private readonly options?: DatabaseManagerOptions,
private readonly databaseCache: Map<string, Promise<Knex>> = new Map(),
) {}
/**
@@ -307,45 +308,57 @@ export class DatabaseManager {
* plugin
*/
private async getDatabase(pluginId: string): Promise<Knex> {
const pluginConfig = new ConfigReader(
this.getConfigForPlugin(pluginId) as JsonObject,
);
const databaseName = this.getDatabaseName(pluginId);
if (databaseName && this.getEnsureExistsConfig(pluginId)) {
try {
await ensureDatabaseExists(pluginConfig, databaseName);
} catch (error) {
throw new Error(
`Failed to connect to the database to make sure that '${databaseName}' exists, ${error}`,
);
}
if (this.databaseCache.has(pluginId)) {
return this.databaseCache.get(pluginId)!;
}
let schemaOverrides;
if (this.getPluginDivisionModeConfig() === 'schema') {
schemaOverrides = this.getSchemaOverrides(pluginId);
if (this.getEnsureExistsConfig(pluginId)) {
const clientPromise = Promise.resolve().then(async () => {
const pluginConfig = new ConfigReader(
this.getConfigForPlugin(pluginId) as JsonObject,
);
const databaseName = this.getDatabaseName(pluginId);
if (databaseName && this.getEnsureExistsConfig(pluginId)) {
try {
await ensureSchemaExists(pluginConfig, pluginId);
await ensureDatabaseExists(pluginConfig, databaseName);
} catch (error) {
throw new Error(
`Failed to connect to the database to make sure that schema for plugin '${pluginId}' exists, ${error}`,
`Failed to connect to the database to make sure that '${databaseName}' exists, ${error}`,
);
}
}
}
const databaseClientOverrides = mergeDatabaseConfig(
{},
this.getDatabaseOverrides(pluginId),
schemaOverrides,
);
let schemaOverrides;
if (this.getPluginDivisionModeConfig() === 'schema') {
schemaOverrides = this.getSchemaOverrides(pluginId);
if (this.getEnsureExistsConfig(pluginId)) {
try {
await ensureSchemaExists(pluginConfig, pluginId);
} catch (error) {
throw new Error(
`Failed to connect to the database to make sure that schema for plugin '${pluginId}' exists, ${error}`,
);
}
}
}
const client = createDatabaseClient(pluginConfig, databaseClientOverrides);
this.startKeepaliveLoop(pluginId, client);
const databaseClientOverrides = mergeDatabaseConfig(
{},
this.getDatabaseOverrides(pluginId),
schemaOverrides,
);
return client;
const client = createDatabaseClient(
pluginConfig,
databaseClientOverrides,
);
this.startKeepaliveLoop(pluginId, client);
return client;
});
this.databaseCache.set(pluginId, clientPromise);
return clientPromise;
}
private startKeepaliveLoop(pluginId: string, client: Knex): void {
@@ -21,7 +21,7 @@ import { notFoundHandler } from './notFoundHandler';
describe('notFoundHandler', () => {
it('handles only missing routes', async () => {
const app = express();
app.use('/exists', (_, res) => res.status(200).send());
app.use('/exists', (_, res) => res.status(200).end());
app.use(notFoundHandler());
const existsResponse = await request(app).get('/exists');
@@ -28,6 +28,6 @@ import { NextFunction, Request, RequestHandler, Response } from 'express';
export function notFoundHandler(): RequestHandler {
/* eslint-disable @typescript-eslint/no-unused-vars */
return (_request: Request, response: Response, _next: NextFunction) => {
response.status(404).send();
response.status(404).end();
};
}
@@ -26,8 +26,8 @@ describe('requestLoggingHandler', () => {
const app = express();
app.use(requestLoggingHandler(logger));
app.use('/exists1', (_, res) => res.status(200).send());
app.use('/exists2', (_, res) => res.status(201).send());
app.use('/exists1', (_, res) => res.status(200).end());
app.use('/exists2', (_, res) => res.status(201).end());
const r = request(app);
await r.get('/exists1');
@@ -55,7 +55,7 @@ export async function statusCheckHandler(
return async (_request: Request, response: Response, next: NextFunction) => {
try {
const status = await statusCheck();
response.status(200).header('').send(status);
response.status(200).json(status);
} catch (err) {
next(err);
}
+8
View File
@@ -1,5 +1,13 @@
# @backstage/backend-defaults
## 0.1.2-next.1
### Patch Changes
- Updated dependencies
- @backstage/backend-plugin-api@0.1.3-next.1
- @backstage/backend-app-api@0.2.2-next.1
## 0.1.2-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-defaults",
"description": "Backend defaults used by Backstage backend apps",
"version": "0.1.2-next.0",
"version": "0.1.2-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
+10
View File
@@ -1,5 +1,15 @@
# example-backend-next
## 0.0.4-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-scaffolder-backend@1.7.0-next.1
- @backstage/backend-defaults@0.1.2-next.1
- @backstage/plugin-app-backend@0.3.37-next.1
- @backstage/plugin-catalog-backend@1.4.1-next.1
## 0.0.4-next.0
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "example-backend-next",
"version": "0.0.4-next.0",
"version": "0.0.4-next.1",
"main": "dist/index.cjs.js",
"types": "src/index.ts",
"license": "Apache-2.0",
+11
View File
@@ -1,5 +1,16 @@
# @backstage/backend-plugin-api
## 0.1.3-next.1
### Patch Changes
- a35a27df70: Added documentation for `createBackendModule`, with guidelines for choosing a module ID.
- Updated dependencies
- @backstage/backend-common@0.15.2-next.1
- @backstage/backend-tasks@0.3.6-next.1
- @backstage/config@1.0.3-next.1
- @backstage/plugin-permission-common@0.6.5-next.1
## 0.1.3-next.0
### Patch Changes
+1 -1
View File
@@ -71,7 +71,7 @@ export const cacheServiceRef: ServiceRef<PluginCacheManager, 'plugin'>;
// @public (undocumented)
export const configServiceRef: ServiceRef<Config, 'root'>;
// @public (undocumented)
// @public
export function createBackendModule<
TOptions extends object | undefined = undefined,
>(
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-plugin-api",
"description": "Core API used by Backstage backend plugins",
"version": "0.1.3-next.0",
"version": "0.1.3-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
@@ -69,7 +69,18 @@ export interface BackendModuleConfig<TOptions> {
): void;
}
/** @public */
/**
* @public
*
* Creates a new backend module for a given plugin.
*
* The `moduleId` should be equal to the module-specific prefix of the exported name, such
* that the full name is `moduleId + PluginId + "Module"`. For example, a GitHub entity
* provider module for the `catalog` plugin might have the module ID `'githubEntityProvider'`,
* and the full exported name would be `githubEntityProviderCatalogModule`.
*
* The `pluginId` should exactly match the `id` of the plugin that the module extends.
*/
export function createBackendModule<
TOptions extends object | undefined = undefined,
>(
+10
View File
@@ -1,5 +1,15 @@
# @backstage/backend-tasks
## 0.3.6-next.1
### Patch Changes
- Updated dependencies
- @backstage/backend-common@0.15.2-next.1
- @backstage/config@1.0.3-next.1
- @backstage/errors@1.1.2-next.1
- @backstage/types@1.0.0
## 0.3.6-next.0
### Patch Changes
+18
View File
@@ -30,6 +30,11 @@ export interface PluginTaskScheduler {
triggerTask(id: string): Promise<void>;
}
// @public
export function readTaskScheduleDefinitionFromConfig(
config: Config,
): TaskScheduleDefinition;
// @public
export type TaskFunction =
| ((abortSignal: AbortSignal_2) => void | Promise<void>)
@@ -60,6 +65,19 @@ export interface TaskScheduleDefinition {
timeout: Duration | HumanDuration;
}
// @public
export interface TaskScheduleDefinitionConfig {
frequency:
| {
cron: string;
}
| string
| HumanDuration;
initialDelay?: string | HumanDuration;
scope?: 'global' | 'local';
timeout: string | HumanDuration;
}
// @public
export class TaskScheduler {
constructor(databaseManager: DatabaseManager, logger: Logger);
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-tasks",
"description": "Common distributed task management library for Backstage backends",
"version": "0.3.6-next.0",
"version": "0.3.6-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
@@ -14,6 +14,7 @@
* limitations under the License.
*/
export { readTaskScheduleDefinitionFromConfig } from './readTaskScheduleDefinitionFromConfig';
export { TaskScheduler } from './TaskScheduler';
export type {
PluginTaskScheduler,
@@ -21,5 +22,6 @@ export type {
TaskInvocationDefinition,
TaskRunner,
TaskScheduleDefinition,
TaskScheduleDefinitionConfig,
HumanDuration,
} from './types';
@@ -0,0 +1,119 @@
/*
* 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.
*/
import { ConfigReader } from '@backstage/config';
import { Duration } from 'luxon';
import { readTaskScheduleDefinitionFromConfig } from './readTaskScheduleDefinitionFromConfig';
import { HumanDuration } from './types';
describe('readTaskScheduleDefinitionFromConfig', () => {
it('all valid values', () => {
const config = new ConfigReader({
frequency: {
cron: '0 30 * * * *',
},
timeout: 'PT3M',
initialDelay: {
minutes: 20,
},
scope: 'global',
});
const result = readTaskScheduleDefinitionFromConfig(config);
expect((result.frequency as { cron: string }).cron).toBe('0 30 * * * *');
expect(result.timeout).toEqual(Duration.fromISO('PT3M'));
expect((result.initialDelay as HumanDuration).minutes).toEqual(20);
expect(result.scope).toBe('global');
});
it('all valid required values', () => {
const config = new ConfigReader({
frequency: {
cron: '0 30 * * * *',
},
timeout: 'PT3M',
});
const result = readTaskScheduleDefinitionFromConfig(config);
expect((result.frequency as { cron: string }).cron).toBe('0 30 * * * *');
expect(result.timeout).toEqual(Duration.fromISO('PT3M'));
expect(result.initialDelay).toBeUndefined();
expect(result.scope).toBeUndefined();
});
it('fail without required frequency', () => {
const config = new ConfigReader({
timeout: 'PT3M',
});
expect(() => readTaskScheduleDefinitionFromConfig(config)).toThrow(
"Missing required config value at 'frequency'",
);
});
it('fail without required timeout', () => {
const config = new ConfigReader({
frequency: 'PT30M',
});
expect(() => readTaskScheduleDefinitionFromConfig(config)).toThrow(
"Missing required config value at 'timeout'",
);
});
it('invalid frequency value', () => {
const config = new ConfigReader({
frequency: {
invalid: 'value',
},
timeout: 'PT3M',
});
expect(() => readTaskScheduleDefinitionFromConfig(config)).toThrow(
'HumanDuration needs at least one of',
);
});
it('frequency value with additional invalid prop', () => {
const config = new ConfigReader({
frequency: {
minutes: 20,
invalid: 'value',
},
timeout: 'PT3M',
});
expect(() => readTaskScheduleDefinitionFromConfig(config)).toThrow(
'HumanDuration does not contain properties: invalid',
);
});
it('invalid scope value', () => {
const config = new ConfigReader({
frequency: {
years: 2,
},
timeout: 'PT3M',
scope: 'invalid',
});
expect(() => readTaskScheduleDefinitionFromConfig(config)).toThrow(
'Only "global" or "local" are allowed for TaskScheduleDefinition.scope, but got: invalid',
);
});
});
@@ -0,0 +1,102 @@
/*
* 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.
*/
import { Config } from '@backstage/config';
import { JsonObject } from '@backstage/types';
import { HumanDuration, TaskScheduleDefinition } from './types';
import { Duration } from 'luxon';
const propsOfHumanDuration = [
'years',
'months',
'weeks',
'days',
'hours',
'minutes',
'seconds',
'milliseconds',
];
function convertToHumanDuration(config: Config, key: string): HumanDuration {
const props = config.getConfig(key).keys();
if (!props.find(prop => propsOfHumanDuration.includes(prop))) {
throw new Error(
`HumanDuration needs at least one of: ${propsOfHumanDuration}`,
);
}
const invalidProps = props.filter(
prop => !propsOfHumanDuration.includes(prop),
);
if (invalidProps.length > 0) {
throw new Error(
`HumanDuration does not contain properties: ${invalidProps}`,
);
}
return config.get<JsonObject>(key) as HumanDuration;
}
function readDuration(config: Config, key: string): Duration | HumanDuration {
return typeof config.get(key) === 'string'
? Duration.fromISO(config.getString(key))
: convertToHumanDuration(config, key);
}
function readCronOrDuration(
config: Config,
key: string,
): { cron: string } | Duration | HumanDuration {
const value = config.get(key);
if (typeof value === 'object' && (value as { cron?: string }).cron) {
return value as { cron: string };
}
return readDuration(config, key);
}
/**
* Reads a TaskScheduleDefinition from a Config.
* Expects the config not to be the root config,
* but the config for the definition.
*
* @param config - config for a TaskScheduleDefinition.
* @public
*/
export function readTaskScheduleDefinitionFromConfig(
config: Config,
): TaskScheduleDefinition {
const frequency = readCronOrDuration(config, 'frequency');
const timeout = readDuration(config, 'timeout');
const initialDelay = config.has('initialDelay')
? readDuration(config, 'initialDelay')
: undefined;
const scope = config.getOptionalString('scope');
if (scope && !['global', 'local'].includes(scope)) {
throw new Error(
`Only "global" or "local" are allowed for TaskScheduleDefinition.scope, but got: ${scope}`,
);
}
return {
frequency,
timeout,
initialDelay,
scope: scope as 'global' | 'local' | undefined,
};
}
+100 -3
View File
@@ -58,7 +58,7 @@ export interface TaskScheduleDefinition {
*
* @remarks
*
* This is a best effort value; under some circumstances there can be
* This is the best effort value; under some circumstances there can be
* deviations. For example, if the task runtime is longer than the frequency
* and the timeout has not been given or not been exceeded yet, the next
* invocation of this task will be delayed until after the previous one
@@ -112,7 +112,7 @@ export interface TaskScheduleDefinition {
* collaborating on a task that has its `scope` field set to `'global'`, then
* you may still see the task being processed by other long-lived workers,
* while any given single worker is in its initial sleep delay time e.g. after
* a deployment. Therefore this parameter is not useful for "globally" pausing
* a deployment. Therefore, this parameter is not useful for "globally" pausing
* work; its main intended use is for individual machines to get a chance to
* reach some equilibrium at startup before triggering heavy batch workloads.
*/
@@ -128,7 +128,104 @@ export interface TaskScheduleDefinition {
* attempt to ensure that only one worker machine runs the task at a time,
* according to the given cadence. This means that as the number of worker
* hosts increases, the invocation frequency of this task will not go up.
* Instead the load is spread randomly across hosts. This setting is useful
* Instead, the load is spread randomly across hosts. This setting is useful
* for tasks that access shared resources, for example catalog ingestion tasks
* where you do not want many machines to repeatedly import the same data and
* trample over each other.
*
* When the scope is set to `'local'`, there is no concurrency control across
* hosts. Each host runs the task according to the given cadence similarly to
* `setInterval`, but the runtime ensures that there are no overlapping runs.
*
* @defaultValue 'global'
*/
scope?: 'global' | 'local';
}
/**
* Config options for {@link TaskScheduleDefinition}
* that control the scheduling of a task.
*
* @public
*/
export interface TaskScheduleDefinitionConfig {
/**
* How often you want the task to run. The system does its best to avoid
* overlapping invocations.
*
* @remarks
*
* This is the best effort value; under some circumstances there can be
* deviations. For example, if the task runtime is longer than the frequency
* and the timeout has not been given or not been exceeded yet, the next
* invocation of this task will be delayed until after the previous one
* finishes.
*
* This is a required field.
*/
frequency:
| {
/**
* A crontab style string.
*
* @remarks
*
* Overview:
*
* ```
* second (optional)
* minute
* hour
* day of month
* month
* day of week
*
*
* * * * * * *
* ```
*/
cron: string;
}
| string
| HumanDuration;
/**
* The maximum amount of time that a single task invocation can take, before
* it's considered timed out and gets "released" such that a new invocation
* is permitted to take place (possibly, then, on a different worker).
*/
timeout: string | HumanDuration;
/**
* The amount of time that should pass before the first invocation happens.
*
* @remarks
*
* This can be useful in cold start scenarios to stagger or delay some heavy
* compute jobs. If no value is given for this field then the first invocation
* will happen as soon as possible according to the cadence.
*
* NOTE: This is a per-worker delay. If you have a cluster of workers all
* collaborating on a task that has its `scope` field set to `'global'`, then
* you may still see the task being processed by other long-lived workers,
* while any given single worker is in its initial sleep delay time e.g. after
* a deployment. Therefore, this parameter is not useful for "globally" pausing
* work; its main intended use is for individual machines to get a chance to
* reach some equilibrium at startup before triggering heavy batch workloads.
*/
initialDelay?: string | HumanDuration;
/**
* Sets the scope of concurrency control / locking to apply for invocations of
* this task.
*
* @remarks
*
* When the scope is set to the default value `'global'`, the scheduler will
* attempt to ensure that only one worker machine runs the task at a time,
* according to the given cadence. This means that as the number of worker
* hosts increases, the invocation frequency of this task will not go up.
* Instead, the load is spread randomly across hosts. This setting is useful
* for tasks that access shared resources, for example catalog ingestion tasks
* where you do not want many machines to repeatedly import the same data and
* trample over each other.
+11
View File
@@ -1,5 +1,16 @@
# @backstage/backend-test-utils
## 0.1.29-next.1
### Patch Changes
- Updated dependencies
- @backstage/cli@0.20.0-next.1
- @backstage/backend-common@0.15.2-next.1
- @backstage/backend-plugin-api@0.1.3-next.1
- @backstage/backend-app-api@0.2.2-next.1
- @backstage/config@1.0.3-next.1
## 0.1.29-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-test-utils",
"description": "Test helpers library for Backstage backends",
"version": "0.1.29-next.0",
"version": "0.1.29-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
+42
View File
@@ -1,5 +1,47 @@
# example-backend
## 0.2.76-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-auth-backend@0.17.0-next.1
- @backstage/plugin-search-backend@1.1.0-next.1
- @backstage/catalog-client@1.1.1-next.1
- @backstage/backend-common@0.15.2-next.1
- @backstage/plugin-scaffolder-backend@1.7.0-next.1
- @backstage/plugin-search-common@1.1.0-next.1
- @backstage/plugin-search-backend-node@1.0.3-next.1
- @backstage/plugin-search-backend-module-pg@0.4.1-next.1
- @backstage/plugin-search-backend-module-elasticsearch@1.0.3-next.1
- @backstage/plugin-kubernetes-backend@0.7.3-next.1
- @backstage/plugin-tech-insights-backend@0.5.3-next.1
- example-app@0.2.76-next.1
- @backstage/backend-tasks@0.3.6-next.1
- @backstage/catalog-model@1.1.2-next.1
- @backstage/config@1.0.3-next.1
- @backstage/integration@1.3.2-next.1
- @backstage/plugin-app-backend@0.3.37-next.1
- @backstage/plugin-auth-node@0.2.6-next.1
- @backstage/plugin-azure-devops-backend@0.3.16-next.1
- @backstage/plugin-badges-backend@0.1.31-next.1
- @backstage/plugin-catalog-backend@1.4.1-next.1
- @backstage/plugin-code-coverage-backend@0.2.3-next.1
- @backstage/plugin-graphql-backend@0.1.27-next.1
- @backstage/plugin-jenkins-backend@0.1.27-next.1
- @backstage/plugin-kafka-backend@0.2.30-next.1
- @backstage/plugin-permission-backend@0.5.12-next.1
- @backstage/plugin-permission-common@0.6.5-next.1
- @backstage/plugin-permission-node@0.6.6-next.1
- @backstage/plugin-playlist-backend@0.1.1-next.1
- @backstage/plugin-proxy-backend@0.2.31-next.1
- @backstage/plugin-rollbar-backend@0.1.34-next.1
- @backstage/plugin-scaffolder-backend-module-rails@0.4.5-next.1
- @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.21-next.1
- @backstage/plugin-tech-insights-node@0.3.5-next.1
- @backstage/plugin-techdocs-backend@1.3.1-next.1
- @backstage/plugin-todo-backend@0.1.34-next.1
## 0.2.76-next.0
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "example-backend",
"version": "0.2.76-next.0",
"version": "0.2.76-next.1",
"main": "dist/index.cjs.js",
"types": "src/index.ts",
"license": "Apache-2.0",
+9
View File
@@ -1,5 +1,14 @@
# @backstage/catalog-client
## 1.1.1-next.1
### Patch Changes
- 4f2ac624b4: Renamed argument in `validateEntity` from `location` to `locationRef`
- Updated dependencies
- @backstage/catalog-model@1.1.2-next.1
- @backstage/errors@1.1.2-next.1
## 1.1.1-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/catalog-client",
"description": "An isomorphic client for the catalog backend",
"version": "1.1.1-next.0",
"version": "1.1.1-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
+9
View File
@@ -1,5 +1,14 @@
# @backstage/catalog-model
## 1.1.2-next.1
### Patch Changes
- Updated dependencies
- @backstage/config@1.0.3-next.1
- @backstage/errors@1.1.2-next.1
- @backstage/types@1.0.0
## 1.1.2-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/catalog-model",
"description": "Types and validators that help describe the model of a Backstage Catalog",
"version": "1.1.2-next.0",
"version": "1.1.2-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
+13
View File
@@ -1,5 +1,18 @@
# @backstage/cli
## 0.20.0-next.1
### Patch Changes
- 78d5eb299e: Tweak the Jest Caching loader to only operate when in `watch` mode
- Updated dependencies
- @backstage/cli-common@0.1.10
- @backstage/config@1.0.3-next.1
- @backstage/config-loader@1.1.5-next.1
- @backstage/errors@1.1.2-next.1
- @backstage/release-manifests@0.0.6
- @backstage/types@1.0.0
## 0.20.0-next.0
### Minor Changes
+5
View File
@@ -25,6 +25,11 @@ const envOptions = {
enableSourceMaps: Boolean(process.env.ENABLE_SOURCE_MAPS),
};
if (envOptions.nextTests) {
// Needed so that, at import-time, it can hook into Jest's internals.
require('./jestCachingModuleLoader');
}
const transformIgnorePattern = [
'@material-ui',
'ajv',
@@ -21,6 +21,7 @@ const fileTransformCache = new Map();
const scriptTransformCache = new Map();
let runtimeGeneration = 0;
let isWatchMode;
module.exports = class CachingJestRuntime extends JestRuntime {
// Each Jest run creates a new runtime, including when rerunning tests in
@@ -28,6 +29,10 @@ module.exports = class CachingJestRuntime extends JestRuntime {
__runtimeGeneration = runtimeGeneration++;
transformFile(filename, options) {
if (!isWatchMode) {
return super.transformFile(filename, options);
}
const entry = fileTransformCache.get(filename);
if (entry) {
// Only check modification time if it's from a different runtime generation
@@ -79,3 +84,11 @@ module.exports = class CachingJestRuntime extends JestRuntime {
return script;
}
};
// Inject hook into createHasteMap, as it's the only way that we can
// determine (from our scope here) if we're in "watch mode" or not.
const originalCreateHasteMap = JestRuntime.createHasteMap;
JestRuntime.createHasteMap = (config, options = undefined) => {
isWatchMode = options && options.watch;
return originalCreateHasteMap(config, options);
};
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/cli",
"description": "CLI for developing Backstage plugins and apps",
"version": "0.20.0-next.0",
"version": "0.20.0-next.1",
"publishConfig": {
"access": "public"
},
@@ -33,7 +33,7 @@ export async function createRouter(
router.get('/health', (_, response) => {
logger.info('PONG!');
response.send({ status: 'ok' });
response.json({ status: 'ok' });
});
router.use(errorHandler());
return router;
+7
View File
@@ -1,5 +1,12 @@
# @backstage/codemods
## 0.1.40-next.1
### Patch Changes
- Updated dependencies
- @backstage/cli-common@0.1.10
## 0.1.40-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/codemods",
"description": "A collection of codemods for Backstage projects",
"version": "0.1.40-next.0",
"version": "0.1.40-next.1",
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js"
+10
View File
@@ -1,5 +1,15 @@
# @backstage/config-loader
## 1.1.5-next.1
### Patch Changes
- Updated dependencies
- @backstage/cli-common@0.1.10
- @backstage/config@1.0.3-next.1
- @backstage/errors@1.1.2-next.1
- @backstage/types@1.0.0
## 1.1.5-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/config-loader",
"description": "Config loading functionality used by Backstage backend, and CLI",
"version": "1.1.5-next.0",
"version": "1.1.5-next.1",
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
+7
View File
@@ -1,5 +1,12 @@
# @backstage/config
## 1.0.3-next.1
### Patch Changes
- Updated dependencies
- @backstage/types@1.0.0
## 1.0.3-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/config",
"description": "Config API used by Backstage core, backend, and CLI",
"version": "1.0.3-next.0",
"version": "1.0.3-next.1",
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
+11
View File
@@ -1,5 +1,16 @@
# @backstage/core-app-api
## 1.1.1-next.1
### Patch Changes
- 27e6404aba: Fixed a bug where gathered index routes would fail to bind routable extensions. This would typically show up when placing a routable extension in the entity page overview tab.
- Updated dependencies
- @backstage/core-plugin-api@1.0.7-next.1
- @backstage/config@1.0.3-next.1
- @backstage/types@1.0.0
- @backstage/version-bridge@1.0.1
## 1.1.1-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/core-app-api",
"description": "Core app API used by Backstage apps",
"version": "1.1.1-next.0",
"version": "1.1.1-next.1",
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",
@@ -301,7 +301,7 @@ describe('discovery', () => {
HELLO
</AggregationComponent>
<Route path="bar" element={<Extension3 />}>
<AggregationComponent path="baz">
<AggregationComponent path="">
<Extension4>
<Extension5 />
</Extension4>
@@ -322,8 +322,8 @@ describe('discovery', () => {
[ref1, 'foo'],
[ref2, 'foo'],
[ref3, 'bar'],
[ref4, 'baz'],
[ref5, 'baz'],
[ref4, ''],
[ref5, ''],
]);
expect(sortedEntries(routing.parents)).toEqual([
[ref1, undefined],
@@ -337,7 +337,7 @@ describe('discovery', () => {
routeObj(
'bar',
[ref3],
[routeObj('baz', [ref4, ref5], [], 'gathered')],
[routeObj('', [ref4, ref5], [], 'gathered')],
undefined,
plugin,
),
@@ -178,7 +178,7 @@ export const routingV2Collector = createCollector(
}
if (mountPoint) {
if (!ctx?.gatherPath) {
if (ctx?.gatherPath === undefined) {
throw new Error(
`Routable extension "${stringifyNode(
node,
+11
View File
@@ -1,5 +1,16 @@
# @backstage/core-components
## 0.11.2-next.1
### Patch Changes
- Updated dependencies
- @backstage/core-plugin-api@1.0.7-next.1
- @backstage/config@1.0.3-next.1
- @backstage/errors@1.1.2-next.1
- @backstage/theme@0.2.16
- @backstage/version-bridge@1.0.1
## 0.11.2-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/core-components",
"description": "Core components used by Backstage plugins and apps",
"version": "0.11.2-next.0",
"version": "0.11.2-next.1",
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",
+9
View File
@@ -1,5 +1,14 @@
# @backstage/core-plugin-api
## 1.0.7-next.1
### Patch Changes
- Updated dependencies
- @backstage/config@1.0.3-next.1
- @backstage/types@1.0.0
- @backstage/version-bridge@1.0.1
## 1.0.7-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/core-plugin-api",
"description": "Core API used by Backstage plugins",
"version": "1.0.7-next.0",
"version": "1.0.7-next.1",
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",
+8
View File
@@ -1,5 +1,13 @@
# @backstage/create-app
## 0.4.32-next.1
### Patch Changes
- 7c6306fc8a: Initializes a git repository when creating an app using @packages/create-app
- Updated dependencies
- @backstage/cli-common@0.1.10
## 0.4.32-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/create-app",
"description": "A CLI that helps you create your own Backstage app",
"version": "0.4.32-next.0",
"version": "0.4.32-next.1",
"publishConfig": {
"access": "public"
},
+15
View File
@@ -1,5 +1,20 @@
# @backstage/dev-utils
## 1.0.7-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-catalog-react@1.2.0-next.1
- @backstage/core-app-api@1.1.1-next.1
- @backstage/app-defaults@1.0.7-next.1
- @backstage/core-components@0.11.2-next.1
- @backstage/core-plugin-api@1.0.7-next.1
- @backstage/test-utils@1.2.1-next.1
- @backstage/catalog-model@1.1.2-next.1
- @backstage/integration-react@1.1.5-next.1
- @backstage/theme@0.2.16
## 1.0.7-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/dev-utils",
"description": "Utilities for developing Backstage plugins.",
"version": "1.0.7-next.0",
"version": "1.0.7-next.1",
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",
+7
View File
@@ -1,5 +1,12 @@
# @backstage/errors
## 1.1.2-next.1
### Patch Changes
- Updated dependencies
- @backstage/types@1.0.0
## 1.1.2-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/errors",
"description": "Common utilities for error handling within Backstage",
"version": "1.1.2-next.0",
"version": "1.1.2-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
+11
View File
@@ -1,5 +1,16 @@
# @backstage/integration-react
## 1.1.5-next.1
### Patch Changes
- Updated dependencies
- @backstage/core-components@0.11.2-next.1
- @backstage/core-plugin-api@1.0.7-next.1
- @backstage/config@1.0.3-next.1
- @backstage/integration@1.3.2-next.1
- @backstage/theme@0.2.16
## 1.1.5-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/integration-react",
"description": "Frontend package for managing integrations towards external systems",
"version": "1.1.5-next.0",
"version": "1.1.5-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
+8
View File
@@ -1,5 +1,13 @@
# @backstage/integration
## 1.3.2-next.1
### Patch Changes
- Updated dependencies
- @backstage/config@1.0.3-next.1
- @backstage/errors@1.1.2-next.1
## 1.3.2-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/integration",
"description": "Helpers for managing integrations towards external systems",
"version": "1.3.2-next.0",
"version": "1.3.2-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -1,5 +1,24 @@
# techdocs-cli-embedded-app
## 0.2.75-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-catalog@1.6.0-next.1
- @backstage/core-app-api@1.1.1-next.1
- @backstage/cli@0.20.0-next.1
- @backstage/plugin-techdocs@1.3.3-next.1
- @backstage/app-defaults@1.0.7-next.1
- @backstage/core-components@0.11.2-next.1
- @backstage/core-plugin-api@1.0.7-next.1
- @backstage/test-utils@1.2.1-next.1
- @backstage/catalog-model@1.1.2-next.1
- @backstage/config@1.0.3-next.1
- @backstage/integration-react@1.1.5-next.1
- @backstage/theme@0.2.16
- @backstage/plugin-techdocs-react@1.0.5-next.1
## 0.2.75-next.0
### Patch Changes
@@ -1,6 +1,6 @@
{
"name": "techdocs-cli-embedded-app",
"version": "0.2.75-next.0",
"version": "0.2.75-next.1",
"private": true,
"backstage": {
"role": "frontend"
+11
View File
@@ -1,5 +1,16 @@
# @techdocs/cli
## 1.2.2-next.1
### Patch Changes
- Updated dependencies
- @backstage/backend-common@0.15.2-next.1
- @backstage/catalog-model@1.1.2-next.1
- @backstage/cli-common@0.1.10
- @backstage/config@1.0.3-next.1
- @backstage/plugin-techdocs-node@1.4.1-next.1
## 1.2.2-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@techdocs/cli",
"description": "Utility CLI for managing TechDocs sites in Backstage.",
"version": "1.2.2-next.0",
"version": "1.2.2-next.1",
"publishConfig": {
"access": "public"
},
+13
View File
@@ -1,5 +1,18 @@
# @backstage/test-utils
## 1.2.1-next.1
### Patch Changes
- Updated dependencies
- @backstage/core-app-api@1.1.1-next.1
- @backstage/core-plugin-api@1.0.7-next.1
- @backstage/config@1.0.3-next.1
- @backstage/theme@0.2.16
- @backstage/types@1.0.0
- @backstage/plugin-permission-common@0.6.5-next.1
- @backstage/plugin-permission-react@0.4.6-next.1
## 1.2.1-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/test-utils",
"description": "Utilities to test Backstage plugins and apps.",
"version": "1.2.1-next.0",
"version": "1.2.1-next.1",
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",