incorporated some of feedback
Signed-off-by: bnechyporenko <bnechyporenko@bol.com>
This commit is contained in:
@@ -41,23 +41,6 @@ default, we highly recommend you to set that up. Follow our how-to guide
|
||||
[How to add documentation setup to your software templates](./how-to-guides.md#how-to-add-the-documentation-setup-to-your-software-templates)
|
||||
to get started.
|
||||
|
||||
### Use the documentation template
|
||||
|
||||
There could be _some_ situations where you don't want to keep your docs close to
|
||||
your code, but still want to publish documentation - for example, an onboarding
|
||||
tutorial. For this use case, we have put together a documentation template. Your
|
||||
Backstage instance should by default have a documentation template added. If
|
||||
not, copy the catalog locations from the
|
||||
[create-app template](https://github.com/backstage/backstage/blob/master/packages/create-app/templates/default-app/app-config.yaml.hbs)
|
||||
to add the documentation template. The template creates a component with
|
||||
**only** TechDocs configuration and default markdown files, and is otherwise
|
||||
empty.
|
||||
|
||||

|
||||
|
||||
Create an entity from the documentation template and you will get the needed
|
||||
setup for free.
|
||||
|
||||
### Enable documentation for an already existing entity
|
||||
|
||||
Prerequisites:
|
||||
|
||||
@@ -57,7 +57,6 @@
|
||||
"@backstage/plugin-auth-node": "workspace:^",
|
||||
"@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^",
|
||||
"@backstage/plugin-catalog-node": "workspace:^",
|
||||
"@backstage/plugin-events-node": "workspace:^",
|
||||
"@backstage/plugin-permission-common": "workspace:^",
|
||||
"@backstage/plugin-permission-node": "workspace:^",
|
||||
"@backstage/plugin-scaffolder-backend-module-azure": "workspace:^",
|
||||
|
||||
@@ -36,10 +36,11 @@ import {
|
||||
SerializedTask,
|
||||
TaskStatus,
|
||||
TaskEventType,
|
||||
TaskSecrets,
|
||||
} from '@backstage/plugin-scaffolder-node';
|
||||
import { DateTime, Duration } from 'luxon';
|
||||
import { TaskRecovery, TaskSpec } from '@backstage/plugin-scaffolder-common';
|
||||
import { compactEvents } from './taskRecoveryHelper';
|
||||
import { trimEventsTillLastRecovery } from './taskRecoveryHelper';
|
||||
|
||||
const migrationsDir = resolvePackagePath(
|
||||
'@backstage/plugin-scaffolder-backend',
|
||||
@@ -131,6 +132,16 @@ export class DatabaseTaskStore implements TaskStore {
|
||||
}
|
||||
}
|
||||
|
||||
private parseTaskSecrets(taskRow: RawDbTaskRow): TaskSecrets | undefined {
|
||||
try {
|
||||
return taskRow.secrets ? JSON.parse(taskRow.secrets) : undefined;
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Failed to parse secrets of task '${taskRow.id}', ${error}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static async getClient(
|
||||
database: PluginDatabaseManager | Knex,
|
||||
): Promise<Knex> {
|
||||
@@ -255,7 +266,7 @@ export class DatabaseTaskStore implements TaskStore {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const secrets = task.secrets ? JSON.parse(task.secrets) : undefined;
|
||||
const secrets = this.parseTaskSecrets(task);
|
||||
return {
|
||||
id: task.id,
|
||||
spec,
|
||||
@@ -264,7 +275,7 @@ export class DatabaseTaskStore implements TaskStore {
|
||||
createdAt: task.created_at,
|
||||
createdBy: task.created_by ?? undefined,
|
||||
secrets,
|
||||
} as SerializedTask;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -426,7 +437,7 @@ export class DatabaseTaskStore implements TaskStore {
|
||||
}
|
||||
});
|
||||
|
||||
return compactEvents(events);
|
||||
return trimEventsTillLastRecovery(events);
|
||||
}
|
||||
|
||||
async shutdownTask(options: TaskStoreShutDownTaskOptions): Promise<void> {
|
||||
@@ -480,7 +491,9 @@ export class DatabaseTaskStore implements TaskStore {
|
||||
});
|
||||
}
|
||||
|
||||
async recoverTasks(options: TaskStoreRecoverTaskOptions): Promise<string[]> {
|
||||
async recoverTasks(
|
||||
options: TaskStoreRecoverTaskOptions,
|
||||
): Promise<{ id: string }[]> {
|
||||
const taskIdsToRecover: string[] = [];
|
||||
const timeoutS = Duration.fromObject(options.timeout).as('seconds');
|
||||
|
||||
@@ -525,6 +538,6 @@ export class DatabaseTaskStore implements TaskStore {
|
||||
}
|
||||
});
|
||||
|
||||
return taskIdsToRecover;
|
||||
return taskIdsToRecover.map(id => ({ id }));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,7 +418,6 @@ export class NunjucksWorkflowRunner implements WorkflowRunner {
|
||||
|
||||
const context: TemplateContext = {
|
||||
parameters: task.spec.parameters,
|
||||
EXPERIMENTAL_recovery: task.spec.EXPERIMENTAL_recovery,
|
||||
steps: {},
|
||||
user: task.spec.user,
|
||||
};
|
||||
|
||||
@@ -205,7 +205,7 @@ export class StorageTaskBroker implements TaskBroker {
|
||||
});
|
||||
}
|
||||
|
||||
public async recoverTasks(): Promise<boolean> {
|
||||
public async recoverTasks(): Promise<void> {
|
||||
const enabled =
|
||||
(this.config &&
|
||||
this.config.getOptionalBoolean(
|
||||
@@ -214,21 +214,20 @@ export class StorageTaskBroker implements TaskBroker {
|
||||
false;
|
||||
|
||||
if (enabled) {
|
||||
const defaultTimeout = { seconds: 30 };
|
||||
const timeout = readDuration(
|
||||
this.config,
|
||||
'scaffolder.EXPERIMENTAL_recoverTasksTimeout',
|
||||
defaultTimeout,
|
||||
);
|
||||
const recoveredTaskIds =
|
||||
(await this.storage.recoverTasks?.({
|
||||
timeout: readDuration(
|
||||
this.config,
|
||||
'scaffolder.EXPERIMENTAL_recoverTasksTimeout',
|
||||
{
|
||||
seconds: 30,
|
||||
},
|
||||
),
|
||||
timeout,
|
||||
})) ?? [];
|
||||
recoveredTaskIds.forEach(() => {
|
||||
if (recoveredTaskIds.length > 0) {
|
||||
this.signalDispatch();
|
||||
});
|
||||
}
|
||||
}
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,7 +20,7 @@ import { NunjucksWorkflowRunner } from './NunjucksWorkflowRunner';
|
||||
import { Logger } from 'winston';
|
||||
import { TemplateActionRegistry } from '../actions';
|
||||
import { ScmIntegrations } from '@backstage/integration';
|
||||
import { assertError } from '@backstage/errors';
|
||||
import { assertError, stringifyError } from '@backstage/errors';
|
||||
import { TemplateFilter, TemplateGlobal } from '../../lib';
|
||||
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
|
||||
|
||||
@@ -36,6 +36,7 @@ export type TaskWorkerOptions = {
|
||||
};
|
||||
concurrentTasksLimit: number;
|
||||
permissions?: PermissionEvaluator;
|
||||
logger?: Logger;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -74,8 +75,10 @@ export type CreateWorkerOptions = {
|
||||
*/
|
||||
export class TaskWorker {
|
||||
private taskQueue: PQueue;
|
||||
private logger: Logger | undefined;
|
||||
|
||||
private constructor(private readonly options: TaskWorkerOptions) {
|
||||
this.logger = options.logger;
|
||||
this.taskQueue = new PQueue({
|
||||
concurrency: options.concurrentTasksLimit,
|
||||
});
|
||||
@@ -115,7 +118,8 @@ export class TaskWorker {
|
||||
async recoverTasks() {
|
||||
try {
|
||||
await this.options.taskBroker.recoverTasks?.();
|
||||
} catch (_err) {
|
||||
} catch (err) {
|
||||
this.logger?.error(stringifyError(err));
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { compactEvents } from './taskRecoveryHelper';
|
||||
import { trimEventsTillLastRecovery } from './taskRecoveryHelper';
|
||||
import { SerializedTaskEvent } from './types';
|
||||
|
||||
const toLogEvent = (stepId: string) =>
|
||||
@@ -41,7 +41,7 @@ describe('taskRecoveryHelper', () => {
|
||||
|
||||
const events = [...logEvents, toRecoveredEvent('startOver')];
|
||||
|
||||
expect(compactEvents(events)).toEqual({ events: [] });
|
||||
expect(trimEventsTillLastRecovery(events)).toEqual({ events: [] });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import { SerializedTaskEvent } from '@backstage/plugin-scaffolder-node';
|
||||
import { TaskRecoverStrategy } from '@backstage/plugin-scaffolder-common';
|
||||
|
||||
export const compactEvents = (
|
||||
export const trimEventsTillLastRecovery = (
|
||||
events: SerializedTaskEvent[],
|
||||
): { events: SerializedTaskEvent[] } => {
|
||||
const recoveredEventInd = events
|
||||
|
||||
@@ -170,7 +170,9 @@ export interface TaskStore {
|
||||
options: TaskStoreCreateTaskOptions,
|
||||
): Promise<TaskStoreCreateTaskResult>;
|
||||
|
||||
recoverTasks?(options: TaskStoreRecoverTaskOptions): Promise<string[]>;
|
||||
recoverTasks?(
|
||||
options: TaskStoreRecoverTaskOptions,
|
||||
): Promise<{ id: string }[]>;
|
||||
|
||||
getTask(taskId: string): Promise<SerializedTask>;
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ export interface TaskBroker {
|
||||
|
||||
claim(): Promise<TaskContext>;
|
||||
|
||||
recoverTasks?(): Promise<boolean>;
|
||||
recoverTasks?(): Promise<void>;
|
||||
|
||||
dispatch(
|
||||
options: TaskBrokerDispatchOptions,
|
||||
|
||||
@@ -8190,7 +8190,6 @@ __metadata:
|
||||
"@backstage/plugin-auth-node": "workspace:^"
|
||||
"@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^"
|
||||
"@backstage/plugin-catalog-node": "workspace:^"
|
||||
"@backstage/plugin-events-node": "workspace:^"
|
||||
"@backstage/plugin-permission-common": "workspace:^"
|
||||
"@backstage/plugin-permission-node": "workspace:^"
|
||||
"@backstage/plugin-scaffolder-backend-module-azure": "workspace:^"
|
||||
|
||||
Reference in New Issue
Block a user