diff --git a/.changeset/dry-impalas-serve.md b/.changeset/dry-impalas-serve.md new file mode 100644 index 0000000000..3b1f502b9c --- /dev/null +++ b/.changeset/dry-impalas-serve.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-stack-overflow': patch +--- + +fix: fix decode issues in title and author fields in `StackOverflowSearchResultListItem` diff --git a/.changeset/funny-flies-collect.md b/.changeset/funny-flies-collect.md new file mode 100644 index 0000000000..40b8d481ed --- /dev/null +++ b/.changeset/funny-flies-collect.md @@ -0,0 +1,12 @@ +--- +'@backstage/plugin-catalog-backend-module-github': patch +'@backstage/backend-app-api': patch +'@backstage/backend-common': patch +'@backstage/plugin-catalog-backend': patch +'@backstage/eslint-plugin': patch +'@backstage/plugin-auth-backend': patch +'@backstage/repo-tools': patch +'@backstage/cli': patch +--- + +Bump dependency `minimatch` to v9 diff --git a/.changeset/lazy-needles-lick.md b/.changeset/lazy-needles-lick.md new file mode 100644 index 0000000000..990348cf5d --- /dev/null +++ b/.changeset/lazy-needles-lick.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Fix issue where `resolveSafeChildPath` path would incorrectly resolve when operating on a symlink diff --git a/.changeset/olive-mails-tell.md b/.changeset/olive-mails-tell.md new file mode 100644 index 0000000000..5f82656679 --- /dev/null +++ b/.changeset/olive-mails-tell.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-devtools': patch +'@backstage/plugin-linguist': patch +--- + +Updated to use `fetchApi` as per [ADR013](https://backstage.io/docs/architecture-decisions/adrs-adr013) diff --git a/.changeset/poor-beans-cross.md b/.changeset/poor-beans-cross.md new file mode 100644 index 0000000000..34c473a545 --- /dev/null +++ b/.changeset/poor-beans-cross.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-tech-radar': patch +--- + +Fixed an issue with the "moved in direction" table header cell getting squished and becoming unreadable if a timeline description is too long diff --git a/.changeset/renovate-1c2c49d.md b/.changeset/renovate-1c2c49d.md new file mode 100644 index 0000000000..cbf8daa04d --- /dev/null +++ b/.changeset/renovate-1c2c49d.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': patch +--- + +Updated dependency `octokit-plugin-create-pull-request` to `^5.0.0`. diff --git a/.changeset/renovate-5d40e90.md b/.changeset/renovate-5d40e90.md new file mode 100644 index 0000000000..122f57fdb8 --- /dev/null +++ b/.changeset/renovate-5d40e90.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': patch +--- + +Updated dependency `flatted` to `3.3.1`. diff --git a/.changeset/renovate-914f0df.md b/.changeset/renovate-914f0df.md new file mode 100644 index 0000000000..02942d2018 --- /dev/null +++ b/.changeset/renovate-914f0df.md @@ -0,0 +1,11 @@ +--- +'@backstage/plugin-home-react': patch +'@backstage/plugin-home': patch +'@backstage/plugin-scaffolder-react': patch +'@backstage/plugin-scaffolder': patch +--- + +Updated dependency `@rjsf/utils` to `5.17.1`. +Updated dependency `@rjsf/core` to `5.17.1`. +Updated dependency `@rjsf/material-ui` to `5.17.1`. +Updated dependency `@rjsf/validator-ajv8` to `5.17.1`. diff --git a/.changeset/rude-sheep-jam.md b/.changeset/rude-sheep-jam.md new file mode 100644 index 0000000000..75b0354e9c --- /dev/null +++ b/.changeset/rude-sheep-jam.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-azure-devops': minor +--- + +**BREAKING** The `AzureDevOpsClient` no longer requires `identityAPi` but now requires `fetchApi`. + +Updated to use `fetchApi` as per [ADR013](https://backstage.io/docs/architecture-decisions/adrs-adr013) diff --git a/.changeset/six-sloths-listen.md b/.changeset/six-sloths-listen.md new file mode 100644 index 0000000000..47886e3f77 --- /dev/null +++ b/.changeset/six-sloths-listen.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Internal refactor to break out how the router is constructed diff --git a/.changeset/two-planets-beam.md b/.changeset/two-planets-beam.md new file mode 100644 index 0000000000..d500d22853 --- /dev/null +++ b/.changeset/two-planets-beam.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-kubernetes-common': patch +'@backstage/plugin-kubernetes-react': patch +--- + +Add support to fetch data for Daemon Sets and display an accordion in the same way as with Deployments diff --git a/.eslintrc.js b/.eslintrc.js index 2df965ab73..01cad187be 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -23,8 +23,11 @@ module.exports = { 'notice/notice': [ 'error', { - // eslint-disable-next-line no-restricted-syntax - templateFile: path.resolve(__dirname, './scripts/copyright-header.txt'), + templateFile: path.resolve( + // eslint-disable-next-line no-restricted-syntax + __dirname, + './scripts/templates/copyright-header.txt' + ), onNonMatchingHeader: 'replace', }, ], diff --git a/.prettierignore b/.prettierignore index c561036ebb..3a16bd1388 100644 --- a/.prettierignore +++ b/.prettierignore @@ -11,6 +11,7 @@ cli-report.md plugins/scaffolder-backend/sample-templates .vscode dist-types +.eslintrc.js # reduce the barrier for adopters to add themselves ADOPTERS.md diff --git a/OWNERS.md b/OWNERS.md index e9e14aaf83..4c47f28253 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -107,6 +107,20 @@ Scope: The TechDocs plugin and related tooling These incubating project areas have shared ownership with @backstage/maintainers. +### Community Plugins + +Team: @backstage/community-plugins-maintainers + +Scope: Tooling and Community Repo Maintainers for the Backstage [Community Plugins repository](https://github.com/backstage/community-plugins) + +| Name | Organization | GitHub | Discord | +| -------------------- | ------------ | ------------------------------------------- | ------------ | +| Bethany Griggs | Red Hat | [BethGriggs](https://github.com/BethGriggs) | `bethgriggs` | +| Tomas Kral | Red Hat | [kadel](https://github.com/kadel) | `tomkral` | +| André Wanlin | Spotify | [awanlin](https://github.com/awanlin) | `ahhhndre` | +| Philipp Hugenroth | Spotify | [tudi2d](https://github.com/tudi2d) | `tudi2d` | +| Vincenzo Scamporlino | Spotify | [vinzscam](https://github.com/vinzscam) | `vinzscam` | + ### OpenAPI Tooling Team: @backstage/openapi-tooling-maintainers diff --git a/beps/0001-notifications-system/README.md b/beps/0001-notifications-system/README.md index e3507d05fa..e071b36a06 100644 --- a/beps/0001-notifications-system/README.md +++ b/beps/0001-notifications-system/README.md @@ -96,7 +96,6 @@ The notification backend stores notification using the [database service](https: - ID - Read date -- Done date - Saved status - Creation date - Updated date (optional, for scoped notifications) @@ -104,7 +103,8 @@ The notification backend stores notification using the [database service](https: - Title - Description (optional) - Origin - - Link + - Link (optional) + - Additional links (optional) - Recipients - Severity (optional, default normal) - Topic (optional) @@ -113,6 +113,10 @@ The notification backend stores notification using the [database service](https: The recipients is **not** a list of users, but rather a filter that describes who should receive the notification. It must be possible to evaluate this filter in a database query, so that we can efficiently fetch all notifications for a given user. The same filter will also be used by the signal backend to determine which users should receive a signal. +The read date is a timestamp of marking the notifications as read by the user. If missing, the notification is still unread. + +The saved status is a timestamp indicating when/if the user marked the notification for better visibility in the future (to "pin" the message). Can be undefined. + The title is mandatory human-readable text shortly describing the notifications. The description is an optional human-readable text providing more details to the user. @@ -143,6 +147,8 @@ The link is a relative or absolute URL. As an example, it can be used: - by an external system to request an action within an asynchronous task - by a BE plugin to provide link to other part of the Backstage UI (i.e. to the Catalog) +The additional links are an array of title-URL pairs. They can represent immediate actions on the notification (i.e. yes-no) or lead the user to additional details. + The `notification-backend` does not provide any new permissions, since creating notifications can only be done by other backend plugins, while reading notifications can only be done by the authenticated user. It is possible that we want to add a permissions for reading notifications, in particular for admin and impersonation use cases, but that is not part of this proposal or the initial implementation. The `notification-backend` shall provide necessary parameters for paging and filtering notifications from the frontend. @@ -228,7 +234,7 @@ interface NotificationService { Each notification is always routed to individual users unless it's a broadcast. The `notification-backend` will figure out which users will receive a notification based on the `recipients` parameter, resolving it to the concrete list of users at the time of sending the notification. -Each notification contains a `title` and a `link` for user to see further information. The `created`, `id`, `read` and `saved` properties are handled by the backend based and cannot be changed during the notification creation. +Each notification contains a human readable `title`, `origin` and optionally `link` for additional details. The `created`, `id`, `read` and `saved` properties are handled by the backend based and cannot be passed during the notification creation. Calling `sendNotification` should never throw an error so that it doesn't block the current processing. Notifications should be considered as second-level citizens that are not critical if not delivered. @@ -273,37 +279,31 @@ Example signal payload for a new notification: Notification frontend shows users their own notifications in its own page and the number of unread notifications in the main menu item. -By default, notifications that are `undone` will be shown in the notifications view. The notification `read` status is indicated by the UI. +Notifications are set to `read` when the `Mark as read` action is triggered by the user (bulk or single). -Notifications are set to `read` when the notification link is opened or the notification is set as `done` by the user. +Notifications can be saved for better visibility in the future. -Notifications can be set to `done` by the user, and they are filtered out of the main view. +Notifications can be filtered by `read`, `saved`, `content` (text search in title or description), `created` (since multiple predefined options) and `severity`. -Notifications can be saved for later use by the user. - -Notifications can be filtered by their `read`, `done` and `saved` statuses. - -Notifications are displayed in pages. - -User can search for notifications based on their title and description. +Notifications are displayed in pages. To do so, the backend needs to implement filtering and sorting. The following frontend API is added as part of this proposal. #### `NotificationsApi` ```ts -export type NotificationType = 'undone' | 'done' | 'saved'; +export type NotificationSeverity = 'critical' | 'high' | 'normal' | 'low'; export type GetNotificationsOptions = { - type?: NotificationType; offset?: number; limit?: number; search?: string; + createdSince?: Date; + severity?: NotificationSeverity; }; export type NotificationUpdateOptions = { ids: string[]; - done?: boolean; read?: boolean; saved?: boolean; }; @@ -358,7 +358,7 @@ interface SignalApi { - Replace absent signal service with long polling. This requires changes to the `signals` plugin as well. - Render dynamic values with various different React elements such as the `EntityRefLink` for entity references (for example `{{ user:default/john.doe }}`) in the notification payload -- Handle `link` values that use route references. For example instead hard-coding link to `/catalog/default/component/artist-web` it should be possible to use `catalogPlugin.catalogEntity` route reference as a link of the notification. This should also allow using parameters to be passed to the route reference +- Handle `link` values that use route references. For example instead hard-coding link to `/catalog/default/component/artist-web` it should be possible to use `catalogPlugin.catalogEntity` route reference as a link of the notification. This should also allow using parameters to be passed to the route reference. Links to external systems are still supported. - Add support for `analyticsApi` to notification actions like marking notifications done, saved or opening links in the notifications - Add support for user settings to control how notifications are shown to the user and which notifications user wants to receive. This should also include support for different `NotificationProcessor`s that can send notification to external systems - Add a sound to be played when notification is received diff --git a/beps/0004-scaffolder-task-idempotency/README.md b/beps/0004-scaffolder-task-idempotency/README.md index a7e592af39..03569de3d6 100644 --- a/beps/0004-scaffolder-task-idempotency/README.md +++ b/beps/0004-scaffolder-task-idempotency/README.md @@ -4,7 +4,8 @@ status: provisional authors: - 'bnechyporenko@bol.com' - 'benjaminl@spotify.com' -owners: +owners: + - @backstage/scaffolder-maintainers project-areas: - scaffolder creation-date: 2024-01-31 @@ -153,7 +154,7 @@ export function createGithubRepoCreateAction(options: { username: owner, }); - await ctx.checkpoint('v1.task.checkpoint.repo.creation', async () => { + await ctx.checkpoint('repo.creation', async () => { const repoCreationPromise = user.data.type === 'Organization' ? client.rest.repos.createInOrg({ @@ -168,19 +169,16 @@ export function createGithubRepoCreateAction(options: { }); if (secrets) { - await ctx.checkpoint( - 'v1.task.checkpoint.repo.create.variables', - async () => { - for (const [key, value] of Object.entries(repoVariables ?? {})) { - await client.rest.actions.createRepoVariable({ - owner, - repo, - name: key, - value: value, - }); - } - }, - ); + await ctx.checkpoint('repo.create.variables', async () => { + for (const [key, value] of Object.entries(repoVariables ?? {})) { + await client.rest.actions.createRepoVariable({ + owner, + repo, + name: key, + value: value, + }); + } + }); } ctx.output('remoteUrl', newRepo.clone_url); @@ -204,7 +202,7 @@ Checkpoints will allow action authors to create actions where code paths are ign This will be provided on a context object and action of author provide a key and a callback. ```typescript -await ctx.checkpoint('v1.task.checkpoint.repo.creation', async () => { +await ctx.checkpoint('repo.creation', async () => { const { repoUrl } = await client.rest.Repository.create({}); return { repoUrl }; }); @@ -215,7 +213,7 @@ It's going look like: ```json { - "v1.task.checkpoint.repo.creation": { + "repo.creation": { "status": "success", "result": { "repoUrl": "https://github.com/backstage/backstage.git" @@ -224,6 +222,43 @@ It's going look like: } ``` +or a failed attempt as: + +```json +{ + "repo.creation": { + "status": "failed", + "reason": "Namespace is not valid" + } +} +``` + +DatabaseTaskStore will provide two extra methods `saveTaskState` and `getTaskState`. The type of state in API will be +represented as `JsonObject`. + +Task state will be stored in the extra column `state` in the table `tasks` with the next structure: + +```json +{ + "state": { + "checkpoints": { + "repo.creation": { + "status": "success", + "result": { + "repoUrl": "https://github.com/backstage/backstage.git" + } + }, + "repo.add.member": { + "status": "success", + "result": { + "id": "2345" + } + } + } + } +} +``` + ## Release Plan